V10: Fix error when opening recycle bin (#12619)

* Make object type parameter nullable in configuration editor

* Add delete from recycle bin test

* Clean up after test
This commit is contained in:
Mole
2022-06-27 14:41:59 +02:00
committed by GitHub
parent 5988a4c87d
commit 3cfeac94a4
4 changed files with 93 additions and 6 deletions

View File

@@ -1,4 +1,4 @@
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models;
using Umbraco.Cms.Core.Models.ContentEditing;
using Umbraco.Cms.Core.Models.Membership;
using Umbraco.Cms.Core.PropertyEditors;
@@ -80,8 +80,7 @@ public class ListViewContentAppFactory : IContentAppFactory
throw new NullReferenceException("The property editor with alias " + dt.EditorAlias + " does not exist");
}
IDictionary<string, object> listViewConfig =
editor.GetConfigurationEditor().ToConfigurationEditor(dt.Configuration);
IDictionary<string, object?> listViewConfig = editor.GetConfigurationEditor().ToConfigurationEditorNullable(dt.Configuration);
// add the entity type to the config
listViewConfig["entityType"] = entityType;
@@ -90,7 +89,7 @@ public class ListViewContentAppFactory : IContentAppFactory
if (listViewConfig.ContainsKey("tabName"))
{
var configTabName = listViewConfig["tabName"];
if (string.IsNullOrWhiteSpace(configTabName.ToString()) == false)
if (string.IsNullOrWhiteSpace(configTabName?.ToString()) == false)
{
contentApp.Name = configTabName.ToString();
}
@@ -100,7 +99,7 @@ public class ListViewContentAppFactory : IContentAppFactory
if (listViewConfig.ContainsKey("icon"))
{
var configIcon = listViewConfig["icon"];
if (string.IsNullOrWhiteSpace(configIcon.ToString()) == false)
if (string.IsNullOrWhiteSpace(configIcon?.ToString()) == false)
{
contentApp.Icon = configIcon.ToString();
}
@@ -123,7 +122,7 @@ public class ListViewContentAppFactory : IContentAppFactory
Value = null,
View = editor.GetValueEditor().View,
HideLabel = true,
Config = listViewConfig,
ConfigNullable = listViewConfig,
},
};

View File

@@ -26,9 +26,14 @@ public class ContentPropertyDisplay : ContentPropertyBasic
[Required(AllowEmptyStrings = false)]
public string? View { get; set; }
[Obsolete("The value type parameter of the dictionary will be made nullable in V11, use ConfigNullable instead.")]
[DataMember(Name = "config")]
public IDictionary<string, object>? Config { get; set; }
// TODO: Obsolete in V11.
[IgnoreDataMember]
public IDictionary<string, object?>? ConfigNullable { get => Config!; set => Config = value!; }
[DataMember(Name = "hideLabel")]
public bool HideLabel { get; set; }

View File

@@ -73,8 +73,13 @@ public interface IConfigurationEditor
/// Converts the configuration object to values for the configuration editor.
/// </summary>
/// <param name="configuration">The configuration.</param>
[Obsolete("The value type parameter of the dictionary will be made nullable in V11, use ToConfigurationEditorNullable.")]
IDictionary<string, object> ToConfigurationEditor(object? configuration);
// TODO: Obsolete in V11.
IDictionary<string, object?> ToConfigurationEditorNullable(object? configuration) =>
ToConfigurationEditor(configuration)!;
/// <summary>
/// Converts the configuration object to values for the value editor.
/// </summary>

View File

@@ -0,0 +1,78 @@
/// <reference types="Cypress" />
import {
ContentBuilder,
DocumentTypeBuilder,
} from 'umbraco-cypress-testhelpers';
context('Recycle bin', () => {
beforeEach(() => {
cy.umbracoLogin(Cypress.env('username'), Cypress.env('password'));
});
function refreshContentTree() {
// Refresh to update the tree
cy.get('li .umb-tree-root:contains("Content")').should("be.visible").rightclick();
cy.umbracoContextMenuAction("action-refreshNode").click();
// We have to wait in case the execution is slow, otherwise we'll try and click the item before it appears in the UI
cy.get('.umb-tree-item__inner').should('exist', { timeout: 10000 });
}
it('Can delete content from recycle bin', () => {
const contentToDeleteName = "DeleteMe";
const contentToNotDeleteName = "DontDelete";
const testType = "TestType";
cy.umbracoEnsureDocumentTypeNameNotExists(testType);
cy.deleteAllContent();
const docType = new DocumentTypeBuilder()
.withName(testType)
.build();
cy.saveDocumentType(docType).then((savedDocType) => {
const contentToDelete = new ContentBuilder()
.withContentTypeAlias(savedDocType.alias)
.withAction("saveNew")
.addVariant()
.withName(contentToDeleteName)
.withSave(true)
.done()
.build();
const contentToNotDelete = new ContentBuilder()
.withContentTypeAlias(savedDocType.alias)
.withAction("saveNew")
.addVariant()
.withName(contentToNotDeleteName)
.withSave(true)
.done()
.build();
// Put it in the recycle bin
cy.saveContent(contentToDelete).then(savedToDelete => {
cy.deleteContentById(savedToDelete.id);
});
cy.saveContent(contentToNotDelete).then(savedNotToDelete => {
cy.deleteContentById(savedNotToDelete.id)
});
});
refreshContentTree();
cy.umbracoTreeItem('content', ["Recycle Bin"]).click();
cy.get('.umb-content-grid__content').contains(contentToDeleteName).closest('div').click();
cy.umbracoButtonByLabelKey('actions_delete').click();
cy.umbracoButtonByLabelKey('contentTypeEditor_yesDelete').click();
cy.umbracoSuccessNotification().should('be.visible');
cy.get('.umb-content-grid__content').contains(contentToDeleteName).should('not.exist');
cy.umbracoTreeItem('content', ["Recycle Bin", contentToDeleteName]).should('not.exist');
cy.get('.umb-content-grid__content').contains(contentToNotDeleteName).should('be.visible');
cy.umbracoTreeItem('content', ["Recycle Bin", contentToNotDeleteName]).should('be.visible');
cy.deleteAllContent();
cy.umbracoEnsureDocumentTypeNameNotExists(testType);
});
});