diff --git a/src/AccountDeleter/EmptyFeatureFlagService.cs b/src/AccountDeleter/EmptyFeatureFlagService.cs index afb3106e24..277d2e8fdb 100644 --- a/src/AccountDeleter/EmptyFeatureFlagService.cs +++ b/src/AccountDeleter/EmptyFeatureFlagService.cs @@ -296,6 +296,11 @@ public bool IsDisplayUploadWarningV2Enabled(User user) throw new NotImplementedException(); } + public bool IsDisplayPackageReadmeWarningEnabled(User user) + { + throw new NotImplementedException(); + } + public bool IsFrameworkFilteringEnabled(User user) { throw new NotImplementedException(); } diff --git a/src/Bootstrap/dist/css/bootstrap-theme.css b/src/Bootstrap/dist/css/bootstrap-theme.css index f2fd116726..f8adb32ca0 100644 --- a/src/Bootstrap/dist/css/bootstrap-theme.css +++ b/src/Bootstrap/dist/css/bootstrap-theme.css @@ -1598,6 +1598,9 @@ p.frameworktableinfo-text { font-weight: bold; margin-bottom: -1px; } +.page-package-details .body-tabs .nav-tabs > li.active > a.body-warning-tab { + background-color: #fff4ce; +} .page-package-details .body-tabs .nav-tabs > li > a { border-left: 0px; border-right: 0px; diff --git a/src/Bootstrap/less/theme/page-display-package.less b/src/Bootstrap/less/theme/page-display-package.less index 5deac91aea..6f6565dcd2 100644 --- a/src/Bootstrap/less/theme/page-display-package.less +++ b/src/Bootstrap/less/theme/page-display-package.less @@ -423,6 +423,10 @@ margin-bottom: -1px; } + .nav-tabs > li.active > a.body-warning-tab > { + background-color: #fff4ce; + } + .nav-tabs > li > a { border-left: 0px; border-right: 0px; diff --git a/src/GitHubVulnerabilities2Db/Fakes/FakeFeatureFlagService.cs b/src/GitHubVulnerabilities2Db/Fakes/FakeFeatureFlagService.cs index 20b884a364..f9237589d0 100644 --- a/src/GitHubVulnerabilities2Db/Fakes/FakeFeatureFlagService.cs +++ b/src/GitHubVulnerabilities2Db/Fakes/FakeFeatureFlagService.cs @@ -135,6 +135,11 @@ public bool IsDisplayUploadWarningV2Enabled(User user) throw new NotImplementedException(); } + public bool IsDisplayPackageReadmeWarningEnabled(User user) + { + throw new NotImplementedException(); + } + public bool IsODataDatabaseReadOnlyEnabled() { throw new NotImplementedException(); diff --git a/src/NuGetGallery.Services/Configuration/FeatureFlagService.cs b/src/NuGetGallery.Services/Configuration/FeatureFlagService.cs index 8ac41ceee6..80f2860d1e 100644 --- a/src/NuGetGallery.Services/Configuration/FeatureFlagService.cs +++ b/src/NuGetGallery.Services/Configuration/FeatureFlagService.cs @@ -48,6 +48,7 @@ public class FeatureFlagService : IFeatureFlagService private const string MarkdigMdRenderingFlightName = GalleryPrefix + "MarkdigMdRendering"; private const string MarkdigMdSyntaxHighlightFlightName = GalleryPrefix + "MarkdigMdSyntaxHighlight"; private const string DisplayUploadWarningV2FlightName = GalleryPrefix + "DisplayUploadWarningV2"; + private const string DisplayPackageReadmeWarningFlightName = GalleryPrefix + "DisplayPackageReadmeWarning"; private const string DeletePackageApiFlightName = GalleryPrefix + "DeletePackageApi"; private const string ImageAllowlistFlightName = GalleryPrefix + "ImageAllowlist"; private const string DisplayBannerFlightName = GalleryPrefix + "Banner"; @@ -348,6 +349,11 @@ public bool IsDisplayUploadWarningV2Enabled(User user) return _client.IsEnabled(DisplayUploadWarningV2FlightName, user, defaultValue: false); } + public bool IsDisplayPackageReadmeWarningEnabled(User user) + { + return _client.IsEnabled(DisplayPackageReadmeWarningFlightName, user, defaultValue: false); + } + public bool IsDeletePackageApiEnabled(User user) { return _client.IsEnabled(DeletePackageApiFlightName, user, defaultValue: false); diff --git a/src/NuGetGallery.Services/Configuration/IFeatureFlagService.cs b/src/NuGetGallery.Services/Configuration/IFeatureFlagService.cs index ca7d820305..ba5da554de 100644 --- a/src/NuGetGallery.Services/Configuration/IFeatureFlagService.cs +++ b/src/NuGetGallery.Services/Configuration/IFeatureFlagService.cs @@ -273,6 +273,11 @@ public interface IFeatureFlagService /// bool IsDisplayUploadWarningV2Enabled(User user); + /// + /// Whether the new warning of the missing readme is displayed to package authors + /// + bool IsDisplayPackageReadmeWarningEnabled(User user); + /// /// Whether or not the user can delete a package through the API. /// diff --git a/src/NuGetGallery/App_Data/Files/Content/flags.json b/src/NuGetGallery/App_Data/Files/Content/flags.json index 8abeeaada6..e2313044a1 100644 --- a/src/NuGetGallery/App_Data/Files/Content/flags.json +++ b/src/NuGetGallery/App_Data/Files/Content/flags.json @@ -120,6 +120,12 @@ "SiteAdmins": false, "Accounts": [], "Domains": [] + }, + "NuGetGallery.DisplayPackageReadmeWarning": { + "All": true, + "SiteAdmins": false, + "Accounts": [], + "Domains": [] } } } \ No newline at end of file diff --git a/src/NuGetGallery/Controllers/PackagesController.cs b/src/NuGetGallery/Controllers/PackagesController.cs index 39a29f74ec..c1ac87e5c4 100644 --- a/src/NuGetGallery/Controllers/PackagesController.cs +++ b/src/NuGetGallery/Controllers/PackagesController.cs @@ -941,6 +941,8 @@ public virtual async Task DisplayPackage(string id, string version packageRenames, readme); + var canDisplayReadmeWarning = _featureFlagService.IsDisplayPackageReadmeWarningEnabled(currentUser) && !model.HasEmbeddedReadmeFile && model.ReadMeHtml == null; + model.ValidatingTooLong = _validationService.IsValidatingTooLong(package); model.PackageValidationIssues = _validationService.GetLatestPackageValidationIssues(package); model.SymbolsPackageValidationIssues = _validationService.GetLatestPackageValidationIssues(model.LatestSymbolsPackage); @@ -956,6 +958,7 @@ public virtual async Task DisplayPackage(string id, string version model.IsDisplayTargetFrameworkEnabled = _featureFlagService.IsDisplayTargetFrameworkEnabled(currentUser); model.IsComputeTargetFrameworkEnabled = _featureFlagService.IsComputeTargetFrameworkEnabled(); model.IsMarkdigMdSyntaxHighlightEnabled = _featureFlagService.IsMarkdigMdSyntaxHighlightEnabled(); + model.CanDisplayReadmeWarning = canDisplayReadmeWarning; if (model.IsComputeTargetFrameworkEnabled || model.IsDisplayTargetFrameworkEnabled) { diff --git a/src/NuGetGallery/ViewModels/DisplayPackageViewModel.cs b/src/NuGetGallery/ViewModels/DisplayPackageViewModel.cs index 2540018b67..02a1cc8331 100644 --- a/src/NuGetGallery/ViewModels/DisplayPackageViewModel.cs +++ b/src/NuGetGallery/ViewModels/DisplayPackageViewModel.cs @@ -44,6 +44,7 @@ public class DisplayPackageViewModel : ListPackageItemViewModel public bool IsPackageDependentsEnabled { get; set; } public bool IsRecentPackagesNoIndexEnabled { get; set; } public bool IsMarkdigMdSyntaxHighlightEnabled { get; set; } + public bool CanDisplayReadmeWarning { get; set; } public NuGetPackageGitHubInformation GitHubDependenciesInformation { get; set; } public bool HasEmbeddedIcon { get; set; } public bool HasEmbeddedReadmeFile { get; set; } diff --git a/src/NuGetGallery/Views/Packages/DisplayPackage.cshtml b/src/NuGetGallery/Views/Packages/DisplayPackage.cshtml index ae339925a9..beca0292f2 100644 --- a/src/NuGetGallery/Views/Packages/DisplayPackage.cshtml +++ b/src/NuGetGallery/Views/Packages/DisplayPackage.cshtml @@ -530,12 +530,19 @@ role="tab" data-toggle="tab" id="readme-body-tab" - class="body-tab" + class="body-@(Model.CanDisplayReadmeWarning && Model.CanDisplayPrivateMetadata? "warning-" : "")tab" aria-controls="readme-tab" aria-expanded="@(activeBodyTab == "readme" ? "true" : "false")" aria-selected="@(activeBodyTab == "readme" ? "true" : "false")" tabindex="@(activeBodyTab == "readme" ? "0" : "-1")"> - + @if (Model.CanDisplayReadmeWarning && Model.CanDisplayPrivateMetadata) + { + + } + else + { + + } README @@ -670,7 +677,11 @@ } else { - if (Model.CanDisplayPrivateMetadata) + if (Model.CanDisplayPrivateMetadata && Model.CanDisplayReadmeWarning) + { + @ViewHelpers.AlertWarning(@Your package is missing a README. Please update your package to include a README or add a README here.); + } + else if (Model.CanDisplayPrivateMetadata) { @ViewHelpers.AlertWarning(@The package description is shown below. Please update your package to include a README.); } diff --git a/src/VerifyMicrosoftPackage/Fakes/FakeFeatureFlagService.cs b/src/VerifyMicrosoftPackage/Fakes/FakeFeatureFlagService.cs index 757a3d9084..fe4e219a62 100644 --- a/src/VerifyMicrosoftPackage/Fakes/FakeFeatureFlagService.cs +++ b/src/VerifyMicrosoftPackage/Fakes/FakeFeatureFlagService.cs @@ -127,6 +127,8 @@ public class FakeFeatureFlagService : IFeatureFlagService public bool IsDisplayUploadWarningV2Enabled(User user) => throw new NotImplementedException(); + public bool IsDisplayPackageReadmeWarningEnabled(User user) => throw new NotImplementedException(); + public bool IsFrameworkFilteringEnabled(User user) => throw new NotImplementedException(); } }