diff --git a/src/AccountDeleter/EmptyFeatureFlagService.cs b/src/AccountDeleter/EmptyFeatureFlagService.cs index 93a549f4cf..ee700dd835 100644 --- a/src/AccountDeleter/EmptyFeatureFlagService.cs +++ b/src/AccountDeleter/EmptyFeatureFlagService.cs @@ -75,7 +75,10 @@ public bool IsDisplayNuGetPackageExplorerLinkEnabled() { throw new NotImplementedException(); } - + public bool IsDisplayNuGetTrendsLinksEnabled() + { + throw new NotImplementedException(); + } public bool IsDisplayTargetFrameworkEnabled(User user) { throw new NotImplementedException(); diff --git a/src/GitHubVulnerabilities2Db/Fakes/FakeFeatureFlagService.cs b/src/GitHubVulnerabilities2Db/Fakes/FakeFeatureFlagService.cs index 8799c8e50c..f79d756d39 100644 --- a/src/GitHubVulnerabilities2Db/Fakes/FakeFeatureFlagService.cs +++ b/src/GitHubVulnerabilities2Db/Fakes/FakeFeatureFlagService.cs @@ -65,6 +65,11 @@ public bool IsDisplayFuGetLinksEnabled() throw new NotImplementedException(); } + public bool IsDisplayNuGetTrendsLinksEnabled() + { + throw new NotImplementedException(); + } + public bool IsDisplayVulnerabilitiesEnabled() { throw new NotImplementedException(); @@ -309,4 +314,4 @@ public bool IsFrameworkFilteringEnabled(User user) { throw new NotImplementedException(); } } -} \ No newline at end of file +} diff --git a/src/NuGetGallery.Services/Configuration/FeatureFlagService.cs b/src/NuGetGallery.Services/Configuration/FeatureFlagService.cs index 8363e83e06..508026de3a 100644 --- a/src/NuGetGallery.Services/Configuration/FeatureFlagService.cs +++ b/src/NuGetGallery.Services/Configuration/FeatureFlagService.cs @@ -30,6 +30,7 @@ public class FeatureFlagService : IFeatureFlagService private const string ManagePackagesVulnerabilitiesFeatureName = GalleryPrefix + "ManagePackagesVulnerabilities"; private const string DisplayFuGetLinksFeatureName = GalleryPrefix + "DisplayFuGetLinks"; private const string DisplayNuGetPackageExplorerLinkFeatureName = GalleryPrefix + "DisplayNuGetPackageExplorerLink"; + private const string DisplayNuGetTrendsLinkFeatureName = GalleryPrefix + "DisplayNuGetTrendsLink"; private const string ODataReadOnlyDatabaseFeatureName = GalleryPrefix + "ODataReadOnlyDatabase"; private const string PackagesAtomFeedFeatureName = GalleryPrefix + "PackagesAtomFeed"; private const string SearchSideBySideFlightName = GalleryPrefix + "SearchSideBySide"; @@ -170,6 +171,11 @@ public bool IsDisplayNuGetPackageExplorerLinkEnabled() return _client.IsEnabled(DisplayNuGetPackageExplorerLinkFeatureName, defaultValue: false); } + public bool IsDisplayNuGetTrendsLinksEnabled() + { + return _client.IsEnabled(DisplayNuGetTrendsLinkFeatureName, defaultValue: false); + } + public bool AreEmbeddedIconsEnabled(User user) { return _client.IsEnabled(EmbeddedIconFlightName, user, defaultValue: false); @@ -404,4 +410,4 @@ public bool IsFrameworkFilteringEnabled(User user) { return _client.IsEnabled(FrameworkFilteringFeatureName, user, defaultValue: false); } } -} \ No newline at end of file +} diff --git a/src/NuGetGallery.Services/Configuration/IFeatureFlagService.cs b/src/NuGetGallery.Services/Configuration/IFeatureFlagService.cs index 865202edb8..b3d34c83fc 100644 --- a/src/NuGetGallery.Services/Configuration/IFeatureFlagService.cs +++ b/src/NuGetGallery.Services/Configuration/IFeatureFlagService.cs @@ -77,6 +77,11 @@ public interface IFeatureFlagService /// bool IsDisplayFuGetLinksEnabled(); + /// + /// Whether or not a nugettrends.com link is visible on a package's details page. + /// + bool IsDisplayNuGetTrendsLinksEnabled(); + /// /// Whether or not a nuget.info (NuGet Package Explorer) link is visible on a package's details page. /// diff --git a/src/NuGetGallery/App_Data/Files/Content/flags.json b/src/NuGetGallery/App_Data/Files/Content/flags.json index 2f2cb0fe6f..7ae1eedaf6 100644 --- a/src/NuGetGallery/App_Data/Files/Content/flags.json +++ b/src/NuGetGallery/App_Data/Files/Content/flags.json @@ -26,6 +26,7 @@ "NuGetGallery.ManagePackagesVulnerabilities": "Enabled", "NuGetGallery.DisplayFuGetLinks": "Enabled", "NuGetGallery.DisplayNuGetPackageExplorerLink": "Enabled", + "NuGetGallery.DisplayNuGetTrendsLink": "Enabled", "NuGetGallery.PatternSetTfmHeuristics": "Enabled", "NuGetGallery.EmbeddedIcons": "Enabled", "NuGetGallery.MarkdigMdRendering": "Enabled", @@ -134,4 +135,4 @@ "Domains": [] } } -} \ No newline at end of file +} diff --git a/src/NuGetGallery/Content/gallery/img/nuget-trends-32x32.png b/src/NuGetGallery/Content/gallery/img/nuget-trends-32x32.png new file mode 100644 index 0000000000..b16c254340 Binary files /dev/null and b/src/NuGetGallery/Content/gallery/img/nuget-trends-32x32.png differ diff --git a/src/NuGetGallery/Content/gallery/img/nuget-trends.svg b/src/NuGetGallery/Content/gallery/img/nuget-trends.svg new file mode 100644 index 0000000000..1275d78e71 --- /dev/null +++ b/src/NuGetGallery/Content/gallery/img/nuget-trends.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + diff --git a/src/NuGetGallery/Controllers/PackagesController.cs b/src/NuGetGallery/Controllers/PackagesController.cs index c991ac3c31..5eac48c04e 100644 --- a/src/NuGetGallery/Controllers/PackagesController.cs +++ b/src/NuGetGallery/Controllers/PackagesController.cs @@ -952,6 +952,7 @@ public virtual async Task DisplayPackage(string id, string version model.IsPackageVulnerabilitiesEnabled = isPackageVulnerabilitiesEnabled; model.IsFuGetLinksEnabled = _featureFlagService.IsDisplayFuGetLinksEnabled(); model.IsNuGetPackageExplorerLinkEnabled = _featureFlagService.IsDisplayNuGetPackageExplorerLinkEnabled(); + model.IsNuGetTrendsLinksEnabled = _featureFlagService.IsDisplayNuGetTrendsLinksEnabled(); model.IsPackageRenamesEnabled = _featureFlagService.IsPackageRenamesEnabled(currentUser); model.IsPackageDependentsEnabled = _featureFlagService.IsPackageDependentsEnabled(currentUser); model.IsRecentPackagesNoIndexEnabled = _featureFlagService.IsRecentPackagesNoIndexEnabled(); diff --git a/src/NuGetGallery/Helpers/ViewModelExtensions/DisplayPackageViewModelFactory.cs b/src/NuGetGallery/Helpers/ViewModelExtensions/DisplayPackageViewModelFactory.cs index 780e0d0a54..9a88de6b93 100644 --- a/src/NuGetGallery/Helpers/ViewModelExtensions/DisplayPackageViewModelFactory.cs +++ b/src/NuGetGallery/Helpers/ViewModelExtensions/DisplayPackageViewModelFactory.cs @@ -179,6 +179,12 @@ private DisplayPackageViewModel SetupCommon( viewModel.NuGetPackageExplorerUrl = nugetPackageExplorerReadyUrl; } + var nugetTrendsUrl = $"https://nugettrends.com/packages?ids={package.Id}"; + if (PackageHelper.TryPrepareUrlForRendering(nugetTrendsUrl, out string nugetTrendsReadyUrl)) + { + viewModel.NuGetTrendsUrl = nugetTrendsReadyUrl; + } + viewModel.EmbeddedLicenseType = package.EmbeddedLicenseType; viewModel.LicenseExpression = package.LicenseExpression; @@ -264,4 +270,4 @@ private static string GetPushedBy(Package package, User currentUser, Dictionary< return pushedByCache[userPushedBy]; } } -} \ No newline at end of file +} diff --git a/src/NuGetGallery/ViewModels/DisplayPackageViewModel.cs b/src/NuGetGallery/ViewModels/DisplayPackageViewModel.cs index a05d32983b..f4269f05e7 100644 --- a/src/NuGetGallery/ViewModels/DisplayPackageViewModel.cs +++ b/src/NuGetGallery/ViewModels/DisplayPackageViewModel.cs @@ -38,6 +38,7 @@ public class DisplayPackageViewModel : ListPackageItemViewModel public bool IsPackageDeprecationEnabled { get; set; } public bool IsPackageVulnerabilitiesEnabled { get; set; } public bool IsFuGetLinksEnabled { get; set; } + public bool IsNuGetTrendsLinksEnabled { get; set; } public bool IsNuGetPackageExplorerLinkEnabled { get; set; } public bool IsPackageRenamesEnabled { get; set; } public bool IsGitHubUsageEnabled { get; set; } @@ -88,6 +89,7 @@ public bool HasNewerRelease public string ProjectUrl { get; set; } public string LicenseUrl { get; set; } public string FuGetUrl { get; set; } + public string NuGetTrendsUrl { get; set; } public string NuGetPackageExplorerUrl { get; set; } public IReadOnlyCollection LicenseNames { get; set; } public string LicenseExpression { get; set; } @@ -146,6 +148,11 @@ public bool CanDisplayFuGetLink() return IsFuGetLinksEnabled && !string.IsNullOrEmpty(FuGetUrl) && Available; } + public bool CanDisplayNuGetTrendsLink() + { + return IsNuGetTrendsLinksEnabled && !string.IsNullOrEmpty(NuGetTrendsUrl) && Available; + } + public bool CanDisplayTargetFrameworks() { return IsDisplayTargetFrameworkEnabled && !Deleted && !IsDotnetNewTemplatePackageType; @@ -166,4 +173,4 @@ public enum RepositoryKind GitHub, } } -} \ No newline at end of file +} diff --git a/src/NuGetGallery/Views/Packages/DisplayPackage.cshtml b/src/NuGetGallery/Views/Packages/DisplayPackage.cshtml index 207be8a2e2..f20c900080 100644 --- a/src/NuGetGallery/Views/Packages/DisplayPackage.cshtml +++ b/src/NuGetGallery/Views/Packages/DisplayPackage.cshtml @@ -1166,6 +1166,23 @@ } + @if (Model.CanDisplayNuGetTrendsLink() && Model.ShowDetailsAndLinks) + { + var disclaimer = "nugettrends.com is a 3rd party website, not controlled by Microsoft. This link is made available to you per the NuGet Terms of Use."; + +
  • + + + Open in NuGet Trends + +
  • + } + @if (!Model.CanReportAsOwner && Model.Available && Model.ShowDetailsAndLinks) {