From 31d58d23d3c987bb4cab08e34ac86514cd8a90e1 Mon Sep 17 00:00:00 2001 From: "Jonatan Gonzalez (HE/HIM)" Date: Mon, 4 Nov 2024 13:43:35 -0800 Subject: [PATCH 01/14] Added resource type for loading from server --- .../Model/PackageSearchMetadata.cs | 2 +- .../PackageMetadataResourceV3Provider.cs | 4 +- .../ReadmeUriTemplateResourceProvider.cs | 35 ++++++++++++++ src/NuGet.Core/NuGet.Protocol/Repository.cs | 1 + .../Resources/PackageMetadataResourceV3.cs | 12 +++++ .../Resources/ReadmeUriTemplateResource.cs | 47 +++++++++++++++++++ src/NuGet.Core/NuGet.Protocol/ServiceTypes.cs | 2 + 7 files changed, 101 insertions(+), 2 deletions(-) create mode 100644 src/NuGet.Core/NuGet.Protocol/Providers/ReadmeUriTemplateResourceProvider.cs create mode 100644 src/NuGet.Core/NuGet.Protocol/Resources/ReadmeUriTemplateResource.cs diff --git a/src/NuGet.Core/NuGet.Protocol/Model/PackageSearchMetadata.cs b/src/NuGet.Core/NuGet.Protocol/Model/PackageSearchMetadata.cs index e8cf3e97452..e848c81b736 100644 --- a/src/NuGet.Core/NuGet.Protocol/Model/PackageSearchMetadata.cs +++ b/src/NuGet.Core/NuGet.Protocol/Model/PackageSearchMetadata.cs @@ -107,7 +107,7 @@ public string Owners public Uri ReadmeUrl { get; private set; } [JsonProperty(PropertyName = JsonProperties.ReadmeFileUrl)] - public string ReadmeFileUrl { get; private set; } + public string ReadmeFileUrl { get; internal set; } [JsonIgnore] public Uri ReportAbuseUrl { get; set; } diff --git a/src/NuGet.Core/NuGet.Protocol/Providers/PackageMetadataResourceV3Provider.cs b/src/NuGet.Core/NuGet.Protocol/Providers/PackageMetadataResourceV3Provider.cs index 0916f2db6d5..259156fc3aa 100644 --- a/src/NuGet.Core/NuGet.Protocol/Providers/PackageMetadataResourceV3Provider.cs +++ b/src/NuGet.Core/NuGet.Protocol/Providers/PackageMetadataResourceV3Provider.cs @@ -23,6 +23,7 @@ public override async Task> TryCreate(SourceReposito { var regResource = await source.GetResourceAsync(token); var reportAbuseResource = await source.GetResourceAsync(token); + var readmeResource = await source.GetResourceAsync(token); var packageDetailsUriResource = await source.GetResourceAsync(token); var httpSourceResource = await source.GetResourceAsync(token); @@ -32,7 +33,8 @@ public override async Task> TryCreate(SourceReposito httpSourceResource.HttpSource, regResource, reportAbuseResource, - packageDetailsUriResource); + packageDetailsUriResource, + readmeResource); } return new Tuple(curResource != null, curResource); diff --git a/src/NuGet.Core/NuGet.Protocol/Providers/ReadmeUriTemplateResourceProvider.cs b/src/NuGet.Core/NuGet.Protocol/Providers/ReadmeUriTemplateResourceProvider.cs new file mode 100644 index 00000000000..95ac9d50753 --- /dev/null +++ b/src/NuGet.Core/NuGet.Protocol/Providers/ReadmeUriTemplateResourceProvider.cs @@ -0,0 +1,35 @@ +// 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.Threading; +using System.Threading.Tasks; +using NuGet.Protocol.Core.Types; + +namespace NuGet.Protocol +{ + internal class ReadmeUriTemplateResourceProvider : ResourceProvider + { + public ReadmeUriTemplateResourceProvider() + : base(typeof(ReadmeUriTemplateResource), + nameof(ReadmeUriTemplateResource), + NuGetResourceProviderPositions.Last) + { + } + + public override async Task> TryCreate(SourceRepository source, CancellationToken token) + { + ReadmeUriTemplateResource resource = null; + var serviceIndex = await source.GetResourceAsync(token); + if (serviceIndex != null) + { + var uriTemplate = serviceIndex.GetServiceEntryUri(ServiceTypes.ReadmeFileUrl)?.OriginalString; + + // construct a new resource + resource = string.IsNullOrWhiteSpace(uriTemplate) ? null : new ReadmeUriTemplateResource(uriTemplate); + } + + return new Tuple(resource != null, resource); + } + } +} diff --git a/src/NuGet.Core/NuGet.Protocol/Repository.cs b/src/NuGet.Core/NuGet.Protocol/Repository.cs index 606a2a06860..9e4a15d2fca 100644 --- a/src/NuGet.Core/NuGet.Protocol/Repository.cs +++ b/src/NuGet.Core/NuGet.Protocol/Repository.cs @@ -53,6 +53,7 @@ public virtual IEnumerable> GetCoreV3() yield return new Lazy(() => new RegistrationResourceV3Provider()); yield return new Lazy(() => new SymbolPackageUpdateResourceV3Provider()); yield return new Lazy(() => new ReportAbuseResourceV3Provider()); + yield return new Lazy(() => new ReadmeUriTemplateResourceProvider()); yield return new Lazy(() => new PackageDetailsUriResourceV3Provider()); yield return new Lazy(() => new ServiceIndexResourceV3Provider()); yield return new Lazy(() => new ODataServiceDocumentResourceV2Provider()); diff --git a/src/NuGet.Core/NuGet.Protocol/Resources/PackageMetadataResourceV3.cs b/src/NuGet.Core/NuGet.Protocol/Resources/PackageMetadataResourceV3.cs index 7ec23f3c980..a28abb30afb 100644 --- a/src/NuGet.Core/NuGet.Protocol/Resources/PackageMetadataResourceV3.cs +++ b/src/NuGet.Core/NuGet.Protocol/Resources/PackageMetadataResourceV3.cs @@ -21,6 +21,7 @@ public class PackageMetadataResourceV3 : PackageMetadataResource { private readonly RegistrationResourceV3 _regResource; private readonly ReportAbuseResourceV3 _reportAbuseResource; + private readonly ReadmeUriTemplateResource _readmeUriTemplateResource; private readonly PackageDetailsUriResourceV3 _packageDetailsUriResource; private readonly HttpSource _client; @@ -36,6 +37,16 @@ public PackageMetadataResourceV3( _packageDetailsUriResource = packageDetailsUriResource; } + internal PackageMetadataResourceV3( + HttpSource client, + RegistrationResourceV3 regResource, + ReportAbuseResourceV3 reportAbuseResource, + PackageDetailsUriResourceV3 packageDetailsUriResource, + ReadmeUriTemplateResource readmeResource) : this(client, regResource, reportAbuseResource, packageDetailsUriResource) + { + _readmeUriTemplateResource = readmeResource; + } + /// PackageId for package we're looking. /// Whether to include PreRelease versions into result. /// Whether to include Unlisted versions into result. @@ -269,6 +280,7 @@ private void ProcessRegistrationPage( { catalogEntry.ReportAbuseUrl = _reportAbuseResource?.GetReportAbuseUrl(catalogEntry.PackageId, catalogEntry.Version); catalogEntry.PackageDetailsUrl = _packageDetailsUriResource?.GetUri(catalogEntry.PackageId, catalogEntry.Version); + catalogEntry.ReadmeFileUrl = _readmeUriTemplateResource?.GetReadmeUrl(catalogEntry.PackageId, catalogEntry.Version); catalogEntry = metadataCache.GetObject(catalogEntry); results.Add(catalogEntry); } diff --git a/src/NuGet.Core/NuGet.Protocol/Resources/ReadmeUriTemplateResource.cs b/src/NuGet.Core/NuGet.Protocol/Resources/ReadmeUriTemplateResource.cs new file mode 100644 index 00000000000..e8c7223862f --- /dev/null +++ b/src/NuGet.Core/NuGet.Protocol/Resources/ReadmeUriTemplateResource.cs @@ -0,0 +1,47 @@ +// 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 NuGet.Protocol.Core.Types; +using NuGet.Versioning; + +#if NETCOREAPP +using System; +#endif + +namespace NuGet.Protocol +{ + internal class ReadmeUriTemplateResource : INuGetResource + { + private readonly string _uriTemplate; + + public ReadmeUriTemplateResource(string uriTemplate) + { + _uriTemplate = uriTemplate; + } + + /// + /// Gets a URL for reporting package abuse. The URL will not be verified to exist. + /// + /// The package id (natural casing) + /// The package version + /// The first URL from the resource, with the URI template applied. + public string GetReadmeUrl(string id, NuGetVersion version) + { + if (_uriTemplate == null) + { + return string.Empty; + } + + var uriString = _uriTemplate +#if NETCOREAPP + .Replace("{lower_id}", id.ToLowerInvariant(), StringComparison.OrdinalIgnoreCase) + .Replace("{lower_version}", version.ToNormalizedString().ToLowerInvariant(), StringComparison.OrdinalIgnoreCase); +#else + .Replace("{lower_id}", id.ToLowerInvariant()) + .Replace("{lower_version}", version.ToNormalizedString().ToLowerInvariant()); +#endif + + return uriString; + } + } +} diff --git a/src/NuGet.Core/NuGet.Protocol/ServiceTypes.cs b/src/NuGet.Core/NuGet.Protocol/ServiceTypes.cs index 729c6ec0bb1..80971cf9088 100644 --- a/src/NuGet.Core/NuGet.Protocol/ServiceTypes.cs +++ b/src/NuGet.Core/NuGet.Protocol/ServiceTypes.cs @@ -18,11 +18,13 @@ public static class ServiceTypes public static readonly string Version510 = "/5.1.0"; internal const string Version670 = "/6.7.0"; internal const string Version6110 = "/6.11.0"; + internal const string Version6120 = "/6.12.0"; public static readonly string[] SearchQueryService = { "SearchQueryService" + Versioned, "SearchQueryService" + Version340, "SearchQueryService" + Version300beta }; public static readonly string[] RegistrationsBaseUrl = { $"RegistrationsBaseUrl{Versioned}", $"RegistrationsBaseUrl{Version360}", $"RegistrationsBaseUrl{Version340}", $"RegistrationsBaseUrl{Version300rc}", $"RegistrationsBaseUrl{Version300beta}", "RegistrationsBaseUrl" }; public static readonly string[] SearchAutocompleteService = { "SearchAutocompleteService" + Versioned, "SearchAutocompleteService" + Version300beta }; public static readonly string[] ReportAbuse = { "ReportAbuseUriTemplate" + Versioned, "ReportAbuseUriTemplate" + Version300 }; + internal static readonly string[] ReadmeFileUrl = { "ReadmeUriTemplate" + Versioned, "ReadmeUriTemplate" + Version6120 }; public static readonly string[] PackageDetailsUriTemplate = { "PackageDetailsUriTemplate" + Version510 }; public static readonly string[] LegacyGallery = { "LegacyGallery" + Versioned, "LegacyGallery" + Version200 }; public static readonly string[] PackagePublish = { "PackagePublish" + Versioned, "PackagePublish" + Version200 }; From e034bc6540ce27733b818e00d44842eb540fdf31 Mon Sep 17 00:00:00 2001 From: "Jonatan Gonzalez (HE/HIM)" Date: Mon, 4 Nov 2024 15:21:18 -0800 Subject: [PATCH 02/14] Add loading message --- .../ViewModels/PackageDetailsTabViewModel.cs | 2 +- .../ViewModels/ReadmePreviewViewModel.cs | 1 + .../Xamls/PackageReadmeControl.xaml.cs | 9 +++------ 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/PackageDetailsTabViewModel.cs b/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/PackageDetailsTabViewModel.cs index a51f64f9e29..be490248dd6 100644 --- a/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/PackageDetailsTabViewModel.cs +++ b/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/PackageDetailsTabViewModel.cs @@ -110,7 +110,7 @@ private void DetailControlModel_PropertyChanged(object sender, PropertyChangedEv { NuGetUIThreadHelper.JoinableTaskFactory.RunAsync(async () => { - if (_readmeTabEnabled) + if (_readmeTabEnabled && e.PropertyName == nameof(DetailControlModel.PackageMetadata)) { await ReadmePreviewViewModel.SetPackageMetadataAsync(DetailControlModel.PackageMetadata, CancellationToken.None); } diff --git a/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs b/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs index ff897fe3b1b..ce3cfb5c4a8 100644 --- a/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs +++ b/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs @@ -60,6 +60,7 @@ public async Task SetPackageMetadataAsync(DetailedPackageMetadata packageMetadat { if (packageMetadata != null && (!string.Equals(packageMetadata.Id, _packageMetadata?.Id) || packageMetadata.Version != _packageMetadata?.Version)) { + ReadmeMarkdown = Resources.Text_Loading; _packageMetadata = packageMetadata; await LoadReadmeAsync(cancellationToken); } diff --git a/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml.cs b/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml.cs index 05a3a80f580..4a0a9bbcb0a 100644 --- a/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml.cs +++ b/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml.cs @@ -7,7 +7,6 @@ using System.Windows; using System.Windows.Controls; using Microsoft.VisualStudio.Markdown.Platform; -using Microsoft.VisualStudio.Shell; using NuGet.PackageManagement.UI.ViewModels; using NuGet.VisualStudio; using NuGet.VisualStudio.Telemetry; @@ -39,7 +38,7 @@ private void ReadmeViewModel_PropertyChanged(object sender, PropertyChangedEvent { if (e.PropertyName == nameof(ReadmePreviewViewModel.ReadmeMarkdown)) { - NuGetUIThreadHelper.JoinableTaskFactory.Run(UpdateMarkdownAsync); + NuGetUIThreadHelper.JoinableTaskFactory.RunAsync(UpdateMarkdownAsync).PostOnFailure(nameof(PackageReadmeControl), nameof(ReadmeViewModel_PropertyChanged)); } } @@ -104,10 +103,8 @@ private void PackageReadmeControl_Unloaded(object sender, RoutedEventArgs e) private void PackageReadmeControl_Loaded(object sender, RoutedEventArgs e) { - ThreadHelper.JoinableTaskFactory.Run(async () => - { - await UpdateMarkdownAsync(); - }); + NuGetUIThreadHelper.JoinableTaskFactory.RunAsync(UpdateMarkdownAsync) + .PostOnFailure(nameof(PackageReadmeControl), nameof(PackageReadmeControl_Loaded)); } } } From 1e473b0fd32219b929058a5f5fb6bff9fa316b07 Mon Sep 17 00:00:00 2001 From: "Jonatan Gonzalez (HE/HIM)" Date: Tue, 5 Nov 2024 11:40:19 -0800 Subject: [PATCH 03/14] Add unit tests --- src/NuGet.Core/NuGet.Protocol/ServiceTypes.cs | 4 +- .../ReadmeUriTemplateResourceProviderTests.cs | 114 ++++++++++++++++++ .../ReadmeUriTemplateResourceTests.cs | 36 ++++++ 3 files changed, 152 insertions(+), 2 deletions(-) create mode 100644 test/NuGet.Core.Tests/NuGet.Protocol.Tests/Providers/ReadmeUriTemplateResourceProviderTests.cs create mode 100644 test/NuGet.Core.Tests/NuGet.Protocol.Tests/ReadmeUriTemplateResourceTests.cs diff --git a/src/NuGet.Core/NuGet.Protocol/ServiceTypes.cs b/src/NuGet.Core/NuGet.Protocol/ServiceTypes.cs index 80971cf9088..a8adc9e0cf3 100644 --- a/src/NuGet.Core/NuGet.Protocol/ServiceTypes.cs +++ b/src/NuGet.Core/NuGet.Protocol/ServiceTypes.cs @@ -18,13 +18,13 @@ public static class ServiceTypes public static readonly string Version510 = "/5.1.0"; internal const string Version670 = "/6.7.0"; internal const string Version6110 = "/6.11.0"; - internal const string Version6120 = "/6.12.0"; + internal const string Version6130 = "/6.13.0"; public static readonly string[] SearchQueryService = { "SearchQueryService" + Versioned, "SearchQueryService" + Version340, "SearchQueryService" + Version300beta }; public static readonly string[] RegistrationsBaseUrl = { $"RegistrationsBaseUrl{Versioned}", $"RegistrationsBaseUrl{Version360}", $"RegistrationsBaseUrl{Version340}", $"RegistrationsBaseUrl{Version300rc}", $"RegistrationsBaseUrl{Version300beta}", "RegistrationsBaseUrl" }; public static readonly string[] SearchAutocompleteService = { "SearchAutocompleteService" + Versioned, "SearchAutocompleteService" + Version300beta }; public static readonly string[] ReportAbuse = { "ReportAbuseUriTemplate" + Versioned, "ReportAbuseUriTemplate" + Version300 }; - internal static readonly string[] ReadmeFileUrl = { "ReadmeUriTemplate" + Versioned, "ReadmeUriTemplate" + Version6120 }; + internal static readonly string[] ReadmeFileUrl = { "ReadmeUriTemplate" + Versioned, "ReadmeUriTemplate" + Version6130 }; public static readonly string[] PackageDetailsUriTemplate = { "PackageDetailsUriTemplate" + Version510 }; public static readonly string[] LegacyGallery = { "LegacyGallery" + Versioned, "LegacyGallery" + Version200 }; public static readonly string[] PackagePublish = { "PackagePublish" + Versioned, "PackagePublish" + Version200 }; diff --git a/test/NuGet.Core.Tests/NuGet.Protocol.Tests/Providers/ReadmeUriTemplateResourceProviderTests.cs b/test/NuGet.Core.Tests/NuGet.Protocol.Tests/Providers/ReadmeUriTemplateResourceProviderTests.cs new file mode 100644 index 00000000000..cc2953dbaf4 --- /dev/null +++ b/test/NuGet.Core.Tests/NuGet.Protocol.Tests/Providers/ReadmeUriTemplateResourceProviderTests.cs @@ -0,0 +1,114 @@ +// 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.Threading; +using System.Threading.Tasks; +using Moq; +using Newtonsoft.Json.Linq; +using NuGet.Configuration; +using NuGet.Protocol.Core.Types; +using NuGet.Versioning; +using Xunit; + +namespace NuGet.Protocol.Tests.Providers +{ + public class ReadmeUriTemplateResourceProviderTests + { + private const string ResourceType = "ReadmeUriTemplate/6.13.0"; + + private readonly PackageSource _packageSource; + private readonly ReadmeUriTemplateResourceProvider _target; + + public ReadmeUriTemplateResourceProviderTests() + { + _packageSource = new PackageSource("https://unit.test"); + _target = new ReadmeUriTemplateResourceProvider(); + } + + [Fact] + public async Task TryCreate_WhenResourceDoesNotExist_ReturnsNull() + { + var resourceProviders = new ResourceProvider[] + { + CreateServiceIndexResourceV3Provider(), + _target + }; + var sourceRepository = new SourceRepository(_packageSource, resourceProviders); + + Tuple result = await _target.TryCreate(sourceRepository, CancellationToken.None); + + Assert.False(result.Item1); + Assert.Null(result.Item2); + } + + [Fact] + public async Task TryCreate_WhenResourceExists_ReturnsValidResourceAsync() + { + var serviceEntry = new RawServiceIndexEntry("https://unit.test/packages/{lower_id}/{lower_version}/readme", ResourceType); + var resourceProviders = new ResourceProvider[] + { + CreateServiceIndexResourceV3Provider(serviceEntry), + _target + }; + var sourceRepository = new SourceRepository(_packageSource, resourceProviders); + + Tuple result = await _target.TryCreate(sourceRepository, CancellationToken.None); + + Assert.True(result.Item1); + Assert.IsType(result.Item2); + Assert.Equal( + "https://unit.test/packages/mypackage/1.0.0/readme", + ((ReadmeUriTemplateResource)result.Item2).GetReadmeUrl("MyPackage", NuGetVersion.Parse("1.0.0"))); + } + + private static ServiceIndexResourceV3Provider CreateServiceIndexResourceV3Provider(params RawServiceIndexEntry[] entries) + { + var provider = new Mock(); + + provider.Setup(x => x.Name) + .Returns(nameof(ServiceIndexResourceV3Provider)); + provider.Setup(x => x.ResourceType) + .Returns(typeof(ServiceIndexResourceV3)); + + var resources = new JArray(); + + foreach (var entry in entries) + { + resources.Add( + new JObject( + new JProperty("@id", entry.Uri), + new JProperty("@type", entry.Type))); + } + + var index = new JObject(); + + index.Add("version", "3.0.0"); + index.Add("resources", resources); + index.Add("@context", + new JObject( + new JProperty("@vocab", "http://schema.nuget.org/schema#"), + new JProperty("comment", "http://www.w3.org/2000/01/rdf-schema#comment"))); + + var serviceIndexResource = new ServiceIndexResourceV3(index, DateTime.UtcNow); + var tryCreateResult = new Tuple(true, serviceIndexResource); + + provider.Setup(x => x.TryCreate(It.IsAny(), It.IsAny())) + .Returns(Task.FromResult(tryCreateResult)); + + return provider.Object; + } + + private class RawServiceIndexEntry + { + public RawServiceIndexEntry(string uri, string type) + { + Uri = uri; + Type = type ?? throw new ArgumentNullException(nameof(type)); + } + + public string Uri { get; } + public string Type { get; } + } + } +} diff --git a/test/NuGet.Core.Tests/NuGet.Protocol.Tests/ReadmeUriTemplateResourceTests.cs b/test/NuGet.Core.Tests/NuGet.Protocol.Tests/ReadmeUriTemplateResourceTests.cs new file mode 100644 index 00000000000..4fc29638c39 --- /dev/null +++ b/test/NuGet.Core.Tests/NuGet.Protocol.Tests/ReadmeUriTemplateResourceTests.cs @@ -0,0 +1,36 @@ +// 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 NuGet.Versioning; +using Xunit; + +namespace NuGet.Protocol.Tests +{ + public class ReadmeUriTemplateResourceTests + { + [Theory] + [InlineData("")] + [InlineData(null)] + public void ReadmeUriTemplateResource_GetReadmeUrl_BlankTemplate_ReturnsEmptyString(string uriTemplate) + { + string expectedResult = string.Empty; + var resource = new ReadmeUriTemplateResource(uriTemplate); + + var actual = resource.GetReadmeUrl("TestPackage", NuGetVersion.Parse("1.0.0")); + + Assert.Equal(expectedResult, actual); + } + + [Fact] + public void ReadmeUriTemplateResource_GetReadmeUrl_ReturnsFormedUrl() + { + const string uriTemplate = "https://test.nuget.org/{lower_id}/{lower_version}/readme"; + const string expectedResult = "https://test.nuget.org/testpackage/1.0.0/readme"; + var resource = new ReadmeUriTemplateResource(uriTemplate); + + var actual = resource.GetReadmeUrl("TestPackage", NuGetVersion.Parse("1.0.0")); + + Assert.Equal(expectedResult, actual.ToString()); + } + } +} From ed4366929c28f9e71e14b46cf89595d0e2272231 Mon Sep 17 00:00:00 2001 From: "Jonatan Gonzalez (HE/HIM)" Date: Wed, 6 Nov 2024 12:18:28 -0800 Subject: [PATCH 04/14] Fix comment, add check for null --- .../NuGet.Protocol/Resources/PackageMetadataResourceV3.cs | 5 ++++- .../NuGet.Protocol/Resources/ReadmeUriTemplateResource.cs | 6 +++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/NuGet.Core/NuGet.Protocol/Resources/PackageMetadataResourceV3.cs b/src/NuGet.Core/NuGet.Protocol/Resources/PackageMetadataResourceV3.cs index a28abb30afb..f32598f4aae 100644 --- a/src/NuGet.Core/NuGet.Protocol/Resources/PackageMetadataResourceV3.cs +++ b/src/NuGet.Core/NuGet.Protocol/Resources/PackageMetadataResourceV3.cs @@ -280,7 +280,10 @@ private void ProcessRegistrationPage( { catalogEntry.ReportAbuseUrl = _reportAbuseResource?.GetReportAbuseUrl(catalogEntry.PackageId, catalogEntry.Version); catalogEntry.PackageDetailsUrl = _packageDetailsUriResource?.GetUri(catalogEntry.PackageId, catalogEntry.Version); - catalogEntry.ReadmeFileUrl = _readmeUriTemplateResource?.GetReadmeUrl(catalogEntry.PackageId, catalogEntry.Version); + if (string.IsNullOrWhiteSpace(catalogEntry.ReadmeFileUrl)) + { + catalogEntry.ReadmeFileUrl = _readmeUriTemplateResource?.GetReadmeUrl(catalogEntry.PackageId, catalogEntry.Version); + } catalogEntry = metadataCache.GetObject(catalogEntry); results.Add(catalogEntry); } diff --git a/src/NuGet.Core/NuGet.Protocol/Resources/ReadmeUriTemplateResource.cs b/src/NuGet.Core/NuGet.Protocol/Resources/ReadmeUriTemplateResource.cs index e8c7223862f..665f3ecc3c9 100644 --- a/src/NuGet.Core/NuGet.Protocol/Resources/ReadmeUriTemplateResource.cs +++ b/src/NuGet.Core/NuGet.Protocol/Resources/ReadmeUriTemplateResource.cs @@ -20,11 +20,11 @@ public ReadmeUriTemplateResource(string uriTemplate) } /// - /// Gets a URL for reporting package abuse. The URL will not be verified to exist. + /// Get the URL for downloading the readme file. /// - /// The package id (natural casing) + /// The package id /// The package version - /// The first URL from the resource, with the URI template applied. + /// URL to download README, built using the URI template. public string GetReadmeUrl(string id, NuGetVersion version) { if (_uriTemplate == null) From ed65992fec6bbd2b8efd5f8d00b8666de819f89f Mon Sep 17 00:00:00 2001 From: "Jonatan Gonzalez (He/Him)" Date: Wed, 20 Nov 2024 15:57:54 -0800 Subject: [PATCH 05/14] remove call to GetReadmeUrl --- .../Providers/ReadmeUriTemplateResourceProviderTests.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/NuGet.Core.Tests/NuGet.Protocol.Tests/Providers/ReadmeUriTemplateResourceProviderTests.cs b/test/NuGet.Core.Tests/NuGet.Protocol.Tests/Providers/ReadmeUriTemplateResourceProviderTests.cs index cc2953dbaf4..6f194c7f34b 100644 --- a/test/NuGet.Core.Tests/NuGet.Protocol.Tests/Providers/ReadmeUriTemplateResourceProviderTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Protocol.Tests/Providers/ReadmeUriTemplateResourceProviderTests.cs @@ -57,9 +57,6 @@ public async Task TryCreate_WhenResourceExists_ReturnsValidResourceAsync() Assert.True(result.Item1); Assert.IsType(result.Item2); - Assert.Equal( - "https://unit.test/packages/mypackage/1.0.0/readme", - ((ReadmeUriTemplateResource)result.Item2).GetReadmeUrl("MyPackage", NuGetVersion.Parse("1.0.0"))); } private static ServiceIndexResourceV3Provider CreateServiceIndexResourceV3Provider(params RawServiceIndexEntry[] entries) From a1d2afb43cc366525d1d8015c2fe26a8675501e4 Mon Sep 17 00:00:00 2001 From: "Jonatan Gonzalez (He/Him)" Date: Wed, 20 Nov 2024 16:25:54 -0800 Subject: [PATCH 06/14] remove unused using --- .../Providers/ReadmeUriTemplateResourceProviderTests.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/test/NuGet.Core.Tests/NuGet.Protocol.Tests/Providers/ReadmeUriTemplateResourceProviderTests.cs b/test/NuGet.Core.Tests/NuGet.Protocol.Tests/Providers/ReadmeUriTemplateResourceProviderTests.cs index 6f194c7f34b..24c0e6c21cf 100644 --- a/test/NuGet.Core.Tests/NuGet.Protocol.Tests/Providers/ReadmeUriTemplateResourceProviderTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Protocol.Tests/Providers/ReadmeUriTemplateResourceProviderTests.cs @@ -8,7 +8,6 @@ using Newtonsoft.Json.Linq; using NuGet.Configuration; using NuGet.Protocol.Core.Types; -using NuGet.Versioning; using Xunit; namespace NuGet.Protocol.Tests.Providers From 65fbbfee34726fdb431c46504df3e115472250d1 Mon Sep 17 00:00:00 2001 From: "Jonatan Gonzalez (He/Him)" Date: Thu, 21 Nov 2024 10:54:17 -0800 Subject: [PATCH 07/14] update test to reflect new resource provider count --- test/NuGet.Core.Tests/NuGet.Protocol.Tests/RepositoryTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/NuGet.Core.Tests/NuGet.Protocol.Tests/RepositoryTests.cs b/test/NuGet.Core.Tests/NuGet.Protocol.Tests/RepositoryTests.cs index 0546f38aae5..a08cd7b0249 100644 --- a/test/NuGet.Core.Tests/NuGet.Protocol.Tests/RepositoryTests.cs +++ b/test/NuGet.Core.Tests/NuGet.Protocol.Tests/RepositoryTests.cs @@ -63,7 +63,7 @@ public void Provider_WithDefaultProvider_ReturnsDefaultResourceProviders() int actualCount = resourceProviders.Count(); - Assert.Equal(48, actualCount); + Assert.Equal(49, actualCount); } } } From 9e561cfb08253c8e7f36bc005d861dc5b1d3381c Mon Sep 17 00:00:00 2001 From: "Jonatan Gonzalez (He/Him)" Date: Thu, 21 Nov 2024 13:50:51 -0800 Subject: [PATCH 08/14] add nullable enabled --- .../Providers/ReadmeUriTemplateResourceProvider.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/NuGet.Core/NuGet.Protocol/Providers/ReadmeUriTemplateResourceProvider.cs b/src/NuGet.Core/NuGet.Protocol/Providers/ReadmeUriTemplateResourceProvider.cs index 95ac9d50753..745feb96e14 100644 --- a/src/NuGet.Core/NuGet.Protocol/Providers/ReadmeUriTemplateResourceProvider.cs +++ b/src/NuGet.Core/NuGet.Protocol/Providers/ReadmeUriTemplateResourceProvider.cs @@ -1,5 +1,6 @@ // 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. +#nullable enable using System; using System.Threading; @@ -17,9 +18,9 @@ public ReadmeUriTemplateResourceProvider() { } - public override async Task> TryCreate(SourceRepository source, CancellationToken token) + public override async Task> TryCreate(SourceRepository source, CancellationToken token) { - ReadmeUriTemplateResource resource = null; + ReadmeUriTemplateResource? resource = null; var serviceIndex = await source.GetResourceAsync(token); if (serviceIndex != null) { @@ -29,7 +30,7 @@ public override async Task> TryCreate(SourceReposito resource = string.IsNullOrWhiteSpace(uriTemplate) ? null : new ReadmeUriTemplateResource(uriTemplate); } - return new Tuple(resource != null, resource); + return new Tuple(resource != null, resource); } } } From b47f8d6da45e6efac75c965a1862cc638eefefe5 Mon Sep 17 00:00:00 2001 From: "Jonatan Gonzalez (He/Him)" Date: Thu, 21 Nov 2024 13:58:20 -0800 Subject: [PATCH 09/14] Added comments --- .../Providers/ReadmeUriTemplateResourceProvider.cs | 3 +++ .../NuGet.Protocol/Resources/ReadmeUriTemplateResource.cs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/NuGet.Core/NuGet.Protocol/Providers/ReadmeUriTemplateResourceProvider.cs b/src/NuGet.Core/NuGet.Protocol/Providers/ReadmeUriTemplateResourceProvider.cs index 745feb96e14..6acc478494a 100644 --- a/src/NuGet.Core/NuGet.Protocol/Providers/ReadmeUriTemplateResourceProvider.cs +++ b/src/NuGet.Core/NuGet.Protocol/Providers/ReadmeUriTemplateResourceProvider.cs @@ -9,6 +9,8 @@ namespace NuGet.Protocol { + /// NuGet.Protocol resource provider for . + /// When successful, returns an instance of . internal class ReadmeUriTemplateResourceProvider : ResourceProvider { public ReadmeUriTemplateResourceProvider() @@ -18,6 +20,7 @@ public ReadmeUriTemplateResourceProvider() { } + /// public override async Task> TryCreate(SourceRepository source, CancellationToken token) { ReadmeUriTemplateResource? resource = null; diff --git a/src/NuGet.Core/NuGet.Protocol/Resources/ReadmeUriTemplateResource.cs b/src/NuGet.Core/NuGet.Protocol/Resources/ReadmeUriTemplateResource.cs index 665f3ecc3c9..3f1a38f29b4 100644 --- a/src/NuGet.Core/NuGet.Protocol/Resources/ReadmeUriTemplateResource.cs +++ b/src/NuGet.Core/NuGet.Protocol/Resources/ReadmeUriTemplateResource.cs @@ -10,6 +10,9 @@ namespace NuGet.Protocol { + /// + /// A resource that provides the URI for downloading a README file based on a template. + /// internal class ReadmeUriTemplateResource : INuGetResource { private readonly string _uriTemplate; From dd19e62e2e22c0d72de2f7696c714f597da58f60 Mon Sep 17 00:00:00 2001 From: "Jonatan Gonzalez (He/Him)" Date: Fri, 22 Nov 2024 11:20:05 -0800 Subject: [PATCH 10/14] Fixes from PR --- .../ViewModels/ReadmePreviewViewModel.cs | 26 ++++++++++--------- .../Model/PackageSearchMetadata.cs | 2 +- .../Resources/ReadmeUriTemplateResource.cs | 12 +++++---- 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs b/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs index ce3cfb5c4a8..aed2f3a5b92 100644 --- a/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs +++ b/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs @@ -60,7 +60,6 @@ public async Task SetPackageMetadataAsync(DetailedPackageMetadata packageMetadat { if (packageMetadata != null && (!string.Equals(packageMetadata.Id, _packageMetadata?.Id) || packageMetadata.Version != _packageMetadata?.Version)) { - ReadmeMarkdown = Resources.Text_Loading; _packageMetadata = packageMetadata; await LoadReadmeAsync(cancellationToken); } @@ -73,6 +72,7 @@ private static bool CanRenderLocalReadme(ItemFilter filter) private async Task LoadReadmeAsync(CancellationToken cancellationToken) { + ReadmeMarkdown = Resources.Text_Loading; if (string.IsNullOrWhiteSpace(_packageMetadata.ReadmeFileUrl)) { ReadmeMarkdown = _canRenderLocalReadme && !string.IsNullOrWhiteSpace(_packageMetadata.PackagePath) ? Resources.Text_NoReadme : string.Empty; @@ -91,20 +91,22 @@ private async Task LoadReadmeAsync(CancellationToken cancellationToken) } var readme = Resources.Text_NoReadme; - await ThreadHelper.JoinableTaskFactory.RunAsync(async () => + try { - await TaskScheduler.Default; - using var readmeStream = await _nugetPackageFileService.GetReadmeAsync(readmeUrl, cancellationToken); - if (readmeStream is null) + await ThreadHelper.JoinableTaskFactory.RunAsync(async () => { - return; - } - - using StreamReader streamReader = new StreamReader(readmeStream); - readme = await streamReader.ReadToEndAsync(); - }); + await TaskScheduler.Default; + using var readmeStream = await _nugetPackageFileService.GetReadmeAsync(readmeUrl, cancellationToken); + if (readmeStream is null) + { + return; + } - if (!cancellationToken.IsCancellationRequested) + using StreamReader streamReader = new StreamReader(readmeStream); + readme = await streamReader.ReadToEndAsync(); + }); + } + finally { ReadmeMarkdown = readme; IsVisible = !string.IsNullOrWhiteSpace(readme); diff --git a/src/NuGet.Core/NuGet.Protocol/Model/PackageSearchMetadata.cs b/src/NuGet.Core/NuGet.Protocol/Model/PackageSearchMetadata.cs index e848c81b736..27230ab7542 100644 --- a/src/NuGet.Core/NuGet.Protocol/Model/PackageSearchMetadata.cs +++ b/src/NuGet.Core/NuGet.Protocol/Model/PackageSearchMetadata.cs @@ -106,7 +106,7 @@ public string Owners [JsonConverter(typeof(SafeUriConverter))] public Uri ReadmeUrl { get; private set; } - [JsonProperty(PropertyName = JsonProperties.ReadmeFileUrl)] + [JsonIgnore] public string ReadmeFileUrl { get; internal set; } [JsonIgnore] diff --git a/src/NuGet.Core/NuGet.Protocol/Resources/ReadmeUriTemplateResource.cs b/src/NuGet.Core/NuGet.Protocol/Resources/ReadmeUriTemplateResource.cs index 3f1a38f29b4..de928aecd97 100644 --- a/src/NuGet.Core/NuGet.Protocol/Resources/ReadmeUriTemplateResource.cs +++ b/src/NuGet.Core/NuGet.Protocol/Resources/ReadmeUriTemplateResource.cs @@ -16,6 +16,8 @@ namespace NuGet.Protocol internal class ReadmeUriTemplateResource : INuGetResource { private readonly string _uriTemplate; + private const string LowerId = "{lower_id}"; + private const string LowerVersion = "{lower_version}"; public ReadmeUriTemplateResource(string uriTemplate) { @@ -23,7 +25,7 @@ public ReadmeUriTemplateResource(string uriTemplate) } /// - /// Get the URL for downloading the readme file. + /// Get the URL for downloading the readme file. /// /// The package id /// The package version @@ -37,11 +39,11 @@ public string GetReadmeUrl(string id, NuGetVersion version) var uriString = _uriTemplate #if NETCOREAPP - .Replace("{lower_id}", id.ToLowerInvariant(), StringComparison.OrdinalIgnoreCase) - .Replace("{lower_version}", version.ToNormalizedString().ToLowerInvariant(), StringComparison.OrdinalIgnoreCase); + .Replace(LowerId, id.ToLowerInvariant(), StringComparison.OrdinalIgnoreCase) + .Replace(LowerVersion, version.ToNormalizedString().ToLowerInvariant(), StringComparison.OrdinalIgnoreCase); #else - .Replace("{lower_id}", id.ToLowerInvariant()) - .Replace("{lower_version}", version.ToNormalizedString().ToLowerInvariant()); + .Replace(LowerId, id.ToLowerInvariant()) + .Replace(LowerVersion, version.ToNormalizedString().ToLowerInvariant()); #endif return uriString; From 4e008ad7c5ef675ec563ba32829f147b719a13e0 Mon Sep 17 00:00:00 2001 From: "Jonatan Gonzalez (He/Him)" Date: Fri, 22 Nov 2024 11:51:22 -0800 Subject: [PATCH 11/14] Switch load --- .../ViewModels/ReadmePreviewViewModel.cs | 25 +++++++++++++++++-- .../Xamls/PackageReadmeControl.xaml | 9 ++++++- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs b/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs index aed2f3a5b92..6b48b9732e5 100644 --- a/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs +++ b/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs @@ -18,6 +18,7 @@ public sealed class ReadmePreviewViewModel : TitledPageViewModelBase private string _rawReadme; private DetailedPackageMetadata _packageMetadata; private bool _canRenderLocalReadme; + private bool _isBusy; public ReadmePreviewViewModel(INuGetPackageFileService packageFileService, ItemFilter itemFilter, bool isReadmeFeatureEnabled) { @@ -25,16 +26,33 @@ public ReadmePreviewViewModel(INuGetPackageFileService packageFileService, ItemF _canRenderLocalReadme = CanRenderLocalReadme(itemFilter); _nugetPackageFileService = packageFileService; _errorLoadingReadme = false; + _isBusy = false; _rawReadme = string.Empty; _packageMetadata = null; Title = Resources.Label_Readme_Tab; IsVisible = isReadmeFeatureEnabled; } + public bool IsReadmeReady { get => !IsBusy && !ErrorLoadingReadme; } + public bool ErrorLoadingReadme { get => _errorLoadingReadme; - set => SetAndRaisePropertyChanged(ref _errorLoadingReadme, value); + set + { + SetAndRaisePropertyChanged(ref _errorLoadingReadme, value); + RaisePropertyChanged(nameof(IsReadmeReady)); + } + } + + public bool IsBusy + { + get => _isBusy; + set + { + SetAndRaisePropertyChanged(ref _isBusy, value); + RaisePropertyChanged(nameof(IsReadmeReady)); + } } public string ReadmeMarkdown @@ -72,12 +90,13 @@ private static bool CanRenderLocalReadme(ItemFilter filter) private async Task LoadReadmeAsync(CancellationToken cancellationToken) { - ReadmeMarkdown = Resources.Text_Loading; + IsBusy = true; if (string.IsNullOrWhiteSpace(_packageMetadata.ReadmeFileUrl)) { ReadmeMarkdown = _canRenderLocalReadme && !string.IsNullOrWhiteSpace(_packageMetadata.PackagePath) ? Resources.Text_NoReadme : string.Empty; IsVisible = !string.IsNullOrWhiteSpace(ReadmeMarkdown); ErrorLoadingReadme = false; + IsBusy = false; return; } @@ -87,6 +106,7 @@ private async Task LoadReadmeAsync(CancellationToken cancellationToken) ReadmeMarkdown = string.Empty; IsVisible = false; ErrorLoadingReadme = false; + IsBusy = false; return; } @@ -111,6 +131,7 @@ await ThreadHelper.JoinableTaskFactory.RunAsync(async () => ReadmeMarkdown = readme; IsVisible = !string.IsNullOrWhiteSpace(readme); ErrorLoadingReadme = false; + IsBusy = false; } } } diff --git a/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml b/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml index f582abcf9e1..faa6638da65 100644 --- a/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml +++ b/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml @@ -9,6 +9,8 @@ xmlns:imagingTheme="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Imaging" xmlns:catalog="clr-namespace:Microsoft.VisualStudio.Imaging;assembly=Microsoft.VisualStudio.ImageCatalog" xmlns:ui="clr-namespace:Microsoft.VisualStudio.PlatformUI;assembly=Microsoft.VisualStudio.Utilities" + Background="{DynamicResource {x:Static nuget:Brushes.DetailPaneBackground}}" + Foreground="{DynamicResource {x:Static nuget:Brushes.UIText}}" DataContextChanged="UserControl_DataContextChanged" Unloaded="PackageReadmeControl_Unloaded" Loaded="PackageReadmeControl_Loaded" @@ -28,8 +30,13 @@ x:Uid="descriptionMarkdownPreview" ClipToBounds="True" Focusable="False" - Visibility="{Binding Path=ErrorLoadingReadme, Mode=OneWay, Converter={StaticResource NegatedBooleanToVisibilityConverter}}" + Visibility="{Binding Path=IsReadmeReady, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}" /> + Date: Fri, 22 Nov 2024 12:52:18 -0800 Subject: [PATCH 12/14] Pr comments --- .../ViewModels/ReadmePreviewViewModel.cs | 4 +--- .../Xamls/PackageReadmeControl.xaml | 9 +++------ 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs b/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs index 6b48b9732e5..b858f8a68a9 100644 --- a/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs +++ b/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs @@ -90,13 +90,11 @@ private static bool CanRenderLocalReadme(ItemFilter filter) private async Task LoadReadmeAsync(CancellationToken cancellationToken) { - IsBusy = true; if (string.IsNullOrWhiteSpace(_packageMetadata.ReadmeFileUrl)) { ReadmeMarkdown = _canRenderLocalReadme && !string.IsNullOrWhiteSpace(_packageMetadata.PackagePath) ? Resources.Text_NoReadme : string.Empty; IsVisible = !string.IsNullOrWhiteSpace(ReadmeMarkdown); ErrorLoadingReadme = false; - IsBusy = false; return; } @@ -106,13 +104,13 @@ private async Task LoadReadmeAsync(CancellationToken cancellationToken) ReadmeMarkdown = string.Empty; IsVisible = false; ErrorLoadingReadme = false; - IsBusy = false; return; } var readme = Resources.Text_NoReadme; try { + IsBusy = true; await ThreadHelper.JoinableTaskFactory.RunAsync(async () => { await TaskScheduler.Default; diff --git a/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml b/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml index faa6638da65..5261c4c51b1 100644 --- a/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml +++ b/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml @@ -30,17 +30,14 @@ x:Uid="descriptionMarkdownPreview" ClipToBounds="True" Focusable="False" - Visibility="{Binding Path=IsReadmeReady, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}" - /> + Visibility="{Binding Path=IsReadmeReady, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}" /> + Visibility="{Binding Path=IsBusy, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}" /> + Visibility="{Binding Path=ErrorLoadingReadme, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}" /> From cd95d3b9b0ee164e3f51553622bd93ab00c3f33a Mon Sep 17 00:00:00 2001 From: "Jonatan Gonzalez (He/Him)" Date: Fri, 22 Nov 2024 12:55:27 -0800 Subject: [PATCH 13/14] Ensure error loading is false when starting to load readme --- .../ViewModels/ReadmePreviewViewModel.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs b/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs index b858f8a68a9..32087121b9a 100644 --- a/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs +++ b/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs @@ -111,6 +111,7 @@ private async Task LoadReadmeAsync(CancellationToken cancellationToken) try { IsBusy = true; + ErrorLoadingReadme = false; await ThreadHelper.JoinableTaskFactory.RunAsync(async () => { await TaskScheduler.Default; From 675b0cde328a235f7b0c6ef860dd07f1721aeb35 Mon Sep 17 00:00:00 2001 From: "Jonatan Gonzalez (He/Him)" Date: Fri, 22 Nov 2024 13:00:09 -0800 Subject: [PATCH 14/14] Rename ErrorLoadingReadme to ErrorWithReadme --- .../ViewModels/ReadmePreviewViewModel.cs | 20 +++++++++---------- .../Xamls/PackageReadmeControl.xaml | 2 +- .../Xamls/PackageReadmeControl.xaml.cs | 2 +- .../ViewModels/ReadmePreviewViewModelTests.cs | 14 ++++++------- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs b/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs index 32087121b9a..c28e59d21a2 100644 --- a/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs +++ b/src/NuGet.Clients/NuGet.PackageManagement.UI/ViewModels/ReadmePreviewViewModel.cs @@ -13,7 +13,7 @@ namespace NuGet.PackageManagement.UI.ViewModels { public sealed class ReadmePreviewViewModel : TitledPageViewModelBase { - private bool _errorLoadingReadme; + private bool _errorWithReadme; private INuGetPackageFileService _nugetPackageFileService; private string _rawReadme; private DetailedPackageMetadata _packageMetadata; @@ -25,7 +25,7 @@ public ReadmePreviewViewModel(INuGetPackageFileService packageFileService, ItemF _nugetPackageFileService = packageFileService ?? throw new ArgumentNullException(nameof(packageFileService)); _canRenderLocalReadme = CanRenderLocalReadme(itemFilter); _nugetPackageFileService = packageFileService; - _errorLoadingReadme = false; + _errorWithReadme = false; _isBusy = false; _rawReadme = string.Empty; _packageMetadata = null; @@ -33,14 +33,14 @@ public ReadmePreviewViewModel(INuGetPackageFileService packageFileService, ItemF IsVisible = isReadmeFeatureEnabled; } - public bool IsReadmeReady { get => !IsBusy && !ErrorLoadingReadme; } + public bool IsReadmeReady { get => !IsBusy && !ErrorWithReadme; } - public bool ErrorLoadingReadme + public bool ErrorWithReadme { - get => _errorLoadingReadme; + get => _errorWithReadme; set { - SetAndRaisePropertyChanged(ref _errorLoadingReadme, value); + SetAndRaisePropertyChanged(ref _errorWithReadme, value); RaisePropertyChanged(nameof(IsReadmeReady)); } } @@ -94,7 +94,7 @@ private async Task LoadReadmeAsync(CancellationToken cancellationToken) { ReadmeMarkdown = _canRenderLocalReadme && !string.IsNullOrWhiteSpace(_packageMetadata.PackagePath) ? Resources.Text_NoReadme : string.Empty; IsVisible = !string.IsNullOrWhiteSpace(ReadmeMarkdown); - ErrorLoadingReadme = false; + ErrorWithReadme = false; return; } @@ -103,7 +103,7 @@ private async Task LoadReadmeAsync(CancellationToken cancellationToken) { ReadmeMarkdown = string.Empty; IsVisible = false; - ErrorLoadingReadme = false; + ErrorWithReadme = false; return; } @@ -111,7 +111,7 @@ private async Task LoadReadmeAsync(CancellationToken cancellationToken) try { IsBusy = true; - ErrorLoadingReadme = false; + ErrorWithReadme = false; await ThreadHelper.JoinableTaskFactory.RunAsync(async () => { await TaskScheduler.Default; @@ -129,7 +129,7 @@ await ThreadHelper.JoinableTaskFactory.RunAsync(async () => { ReadmeMarkdown = readme; IsVisible = !string.IsNullOrWhiteSpace(readme); - ErrorLoadingReadme = false; + ErrorWithReadme = false; IsBusy = false; } } diff --git a/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml b/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml index 5261c4c51b1..7ac5326c491 100644 --- a/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml +++ b/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml @@ -38,6 +38,6 @@ + Visibility="{Binding Path=ErrorWithReadme, Mode=OneWay, Converter={StaticResource BooleanToVisibilityConverter}}" /> diff --git a/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml.cs b/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml.cs index 4a0a9bbcb0a..caf94947c14 100644 --- a/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml.cs +++ b/src/NuGet.Clients/NuGet.PackageManagement.UI/Xamls/PackageReadmeControl.xaml.cs @@ -78,7 +78,7 @@ private async Task UpdateMarkdownAsync() } catch (Exception ex) when (ex is ArgumentException || ex is InvalidOperationException) { - ReadmeViewModel.ErrorLoadingReadme = true; + ReadmeViewModel.ErrorWithReadme = true; ReadmeViewModel.ReadmeMarkdown = string.Empty; await TelemetryUtility.PostFaultAsync(ex, nameof(ReadmePreviewViewModel)); } diff --git a/test/NuGet.Clients.Tests/NuGet.PackageManagement.UI.Test/ViewModels/ReadmePreviewViewModelTests.cs b/test/NuGet.Clients.Tests/NuGet.PackageManagement.UI.Test/ViewModels/ReadmePreviewViewModelTests.cs index ecd4a848c0e..8037fec25cf 100644 --- a/test/NuGet.Clients.Tests/NuGet.PackageManagement.UI.Test/ViewModels/ReadmePreviewViewModelTests.cs +++ b/test/NuGet.Clients.Tests/NuGet.PackageManagement.UI.Test/ViewModels/ReadmePreviewViewModelTests.cs @@ -36,7 +36,7 @@ public void Constructor_Defaults() var target = new ReadmePreviewViewModel(mockFileService.Object, ItemFilter.All, true); //Assert - Assert.False(target.ErrorLoadingReadme); + Assert.False(target.ErrorWithReadme); Assert.Equal(string.Empty, target.ReadmeMarkdown); } @@ -56,7 +56,7 @@ public async Task SetPackageMetadataAsync_WithoutReadmeUrl_NoReadmeReturned(stri await target.SetPackageMetadataAsync(package, CancellationToken.None); //Assert - Assert.False(target.ErrorLoadingReadme); + Assert.False(target.ErrorWithReadme); Assert.Equal(string.Empty, target.ReadmeMarkdown); } @@ -77,7 +77,7 @@ public async Task SetCurrentFilter_ItemFilterAll_NoLocalReadmeReturned() await target.ItemFilterChangedAsync(ItemFilter.All); //Assert - Assert.False(target.ErrorLoadingReadme); + Assert.False(target.ErrorWithReadme); Assert.Equal(string.Empty, target.ReadmeMarkdown); } @@ -101,7 +101,7 @@ public async Task SetCurrentFilter_ItemFilterRenderingLocalReadme_LocalReadmeRet await target.ItemFilterChangedAsync(filter); //Assert - Assert.False(target.ErrorLoadingReadme); + Assert.False(target.ErrorWithReadme); Assert.Equal(readmeContents, target.ReadmeMarkdown); } @@ -121,7 +121,7 @@ public async Task SetPackageMetadataAsync_WithLocalReadmeUrl_RenderLocalReadmeTr await target.SetPackageMetadataAsync(package, CancellationToken.None); //Assert - Assert.False(target.ErrorLoadingReadme); + Assert.False(target.ErrorWithReadme); Assert.Equal(readmeContents, target.ReadmeMarkdown); } @@ -141,7 +141,7 @@ public async Task SetPackageMetadataAsync_WithLocalReadmeUrl_RenderLocalReadmeFa await target.SetPackageMetadataAsync(package, CancellationToken.None); //Assert - Assert.False(target.ErrorLoadingReadme); + Assert.False(target.ErrorWithReadme); Assert.Equal(string.Empty, target.ReadmeMarkdown); } @@ -159,7 +159,7 @@ public async Task SetPackageMetadataAsync_WithLocalReadmeUrl_FileNotFound_NoRead await target.SetPackageMetadataAsync(package, CancellationToken.None); //Assert - Assert.False(target.ErrorLoadingReadme); + Assert.False(target.ErrorWithReadme); Assert.Equal(Resources.Text_NoReadme, target.ReadmeMarkdown); } }