Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto Attach the DashboardPart to content types with DashboardWidget stereotype #16911

Merged
merged 29 commits into from
Oct 31, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
8cc594a
Auto Attach the DashboardPart to content types with DashboardWidget s…
MikeAlhayek Oct 18, 2024
ec5178f
cleanup migration
MikeAlhayek Oct 18, 2024
759bc2b
renaming
MikeAlhayek Oct 19, 2024
5466fd5
remove the need to migrate code managed part
MikeAlhayek Oct 20, 2024
7df9062
cleanup events
MikeAlhayek Oct 20, 2024
ab709b8
Merge branch 'main' into ma/code-managed-parts
MikeAlhayek Oct 20, 2024
5d7a605
Typo
Piedone Oct 23, 2024
358a586
Remove IContentDefinitionHandler
MikeAlhayek Oct 23, 2024
7d5ea74
Fix circular reference
MikeAlhayek Oct 23, 2024
8408a96
Typo
Piedone Oct 23, 2024
ceb6703
Code styling
Piedone Oct 23, 2024
645f91b
More code styling
Piedone Oct 23, 2024
657fc4b
throw exception
MikeAlhayek Oct 23, 2024
da9e357
Merge branch 'ma/code-managed-parts' of https://github.com/OrchardCMS…
MikeAlhayek Oct 23, 2024
233865b
Merge branch 'main' into ma/code-managed-parts
MikeAlhayek Oct 24, 2024
80ea5b7
adding release notes
MikeAlhayek Oct 24, 2024
0800bc1
renaming methods
MikeAlhayek Oct 24, 2024
b8245ec
Introduce a new interface IContentDefinitionHandler
MikeAlhayek Oct 24, 2024
d761987
removing the try catch
MikeAlhayek Oct 24, 2024
0b800d6
cleanup
MikeAlhayek Oct 24, 2024
4e1bd7d
Renaming
MikeAlhayek Oct 25, 2024
21174da
apply remove to type and field
MikeAlhayek Oct 25, 2024
73643d6
Update ContentSettings.cs
MikeAlhayek Oct 25, 2024
970dfee
Merge branch 'main' into ma/code-managed-parts
MikeAlhayek Oct 25, 2024
b4bbd43
Merge branch 'main' into ma/code-managed-parts
MikeAlhayek Oct 29, 2024
5f22e55
address feedback
MikeAlhayek Oct 30, 2024
3f87de0
use system-defined instead of isRemovable
MikeAlhayek Oct 30, 2024
03fdcda
renaming
MikeAlhayek Oct 31, 2024
033de90
fix naming
MikeAlhayek Oct 31, 2024
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace OrchardCore.AdminDashboard;

public static class AdminDashboardConstants
{
public const string Stereotype = "DashboardWidget";
}
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,6 @@ public async Task<IActionResult> Update([FromForm] DashboardPartViewModel[] part

private async Task<Dictionary<string, ContentTypeDefinition>> GetDashboardWidgetsAsync()
=> (await _contentDefinitionManager.ListTypeDefinitionsAsync())
.Where(t => t.StereotypeEquals("DashboardWidget"))
.Where(t => t.StereotypeEquals(AdminDashboardConstants.Stereotype))
.ToDictionary(ctd => ctd.Name, ctd => ctd);
}
14 changes: 8 additions & 6 deletions src/OrchardCore.Modules/OrchardCore.AdminDashboard/Migrations.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,10 @@ await SchemaBuilder.AlterIndexTableAsync<DashboardPartIndex>(table => table
"Position")
);

await _contentDefinitionManager.AlterPartDefinitionAsync("DashboardPart", builder => builder
.Attachable()
.WithDescription("Provides a way to add widgets to a dashboard.")
);

await _recipeMigrator.ExecuteAsync($"dashboard-widgets{RecipesConstants.RecipeExtension}", this);

// Shortcut other migration steps on new content definition schemas.
return 3;
return 4;
}

public async Task<int> UpdateFrom1Async()
Expand All @@ -62,4 +57,11 @@ await SchemaBuilder.AlterIndexTableAsync<DashboardPartIndex>(table => table

return 3;
}

public async Task<int> UpdateFrom3Async()
{
await _contentDefinitionManager.DeletePartDefinitionAsync("DashboardPart");

return 4;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
using System.Text.Json.Nodes;
using OrchardCore.AdminDashboard.Models;
using OrchardCore.ContentManagement.Metadata.Records;
using OrchardCore.ContentManagement.Metadata.Settings;
using OrchardCore.ContentTypes.Events;
using OrchardCore.Modules;

namespace OrchardCore.AdminDashboard.Services;

public sealed class DashboardPartContentTypeDefinitionHandler : ContentDefinitionHandlerBase
MikeAlhayek marked this conversation as resolved.
Show resolved Hide resolved
{
public override void BuildingContentType(BuildingContentTypeContext context)
Piedone marked this conversation as resolved.
Show resolved Hide resolved
{
if (!context.Record.Settings.TryGetPropertyValue(nameof(ContentTypeSettings), out var node))
{
return;
}

var settings = node.ToObject<ContentTypeSettings>();

if (settings.Stereotype == null || !string.Equals(settings.Stereotype, AdminDashboardConstants.Stereotype, StringComparison.OrdinalIgnoreCase))
{
return;
}

if (context.Record.ContentTypePartDefinitionRecords.Any(x => x.Name.EqualsOrdinalIgnoreCase(nameof(DashboardPart))))
{
return;
}

context.Record.ContentTypePartDefinitionRecords.Add(new ContentTypePartDefinitionRecord
{
Name = nameof(DashboardPart),
PartName = nameof(DashboardPart),
Settings = new JsonObject()
{
[nameof(ContentSettings)] = JObject.FromObject(new ContentSettings
{
IsCodeManaged = true,
}),
},
});
}

public override void BuildingContentTypePart(BuildingContentTypePartContext context)
{
if (!context.Record.PartName.EqualsOrdinalIgnoreCase(nameof(DashboardPart)))
{
return;
}

var settings = context.Record.Settings[nameof(ContentSettings)]?.ToObject<ContentSettings>()
?? new ContentSettings();

settings.IsCodeManaged = true;

context.Record.Settings[nameof(ContentSettings)] = JObject.FromObject(settings);
}

public override void BuildingContentPartDefinition(BuildingContentPartDefinitionContext context)
{
if (context.Record is not null || context.Name != nameof(DashboardPart))
{
return;
}

context.Record = new ContentPartDefinitionRecord()
{
Name = context.Name,
Settings = new JsonObject()
{
[nameof(ContentPartSettings)] = JObject.FromObject(new ContentPartSettings
{
Attachable = false,
Reusable = true,
}),
[nameof(ContentSettings)] = JObject.FromObject(new ContentSettings
{
IsCodeManaged = true,
}),
},
};
}
}
2 changes: 2 additions & 0 deletions src/OrchardCore.Modules/OrchardCore.AdminDashboard/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using OrchardCore.AdminDashboard.Services;
using OrchardCore.ContentManagement;
using OrchardCore.ContentManagement.Display.ContentDisplay;
using OrchardCore.ContentTypes.Events;
using OrchardCore.Data;
using OrchardCore.Data.Migration;
using OrchardCore.Modules;
Expand Down Expand Up @@ -42,6 +43,7 @@ public override void ConfigureServices(IServiceCollection services)
services.AddScoped<IContentDisplayDriver, DashboardContentDisplayDriver>();

services.AddDataMigration<Migrations>();
services.AddScoped<IContentDefinitionEventHandler, DashboardPartContentTypeDefinitionHandler>();
}

public override void Configure(IApplicationBuilder builder, IEndpointRouteBuilder routes, IServiceProvider serviceProvider)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -414,14 +414,28 @@ public async Task<ActionResult> RemovePart(string id, string name)

var typeViewModel = await _contentDefinitionService.LoadTypeAsync(id);

if (typeViewModel == null || !typeViewModel.TypeDefinition.Parts.Any(p => string.Equals(p.Name, name, StringComparison.OrdinalIgnoreCase)))
if (typeViewModel == null)
{
return NotFound();
}

var partDefinition = typeViewModel.TypeDefinition.Parts.FirstOrDefault(p => string.Equals(p.Name, name, StringComparison.OrdinalIgnoreCase));

if (partDefinition == null)
{
return NotFound();
}

await _contentDefinitionService.RemovePartFromTypeAsync(name, id);
try
{
await _contentDefinitionService.RemovePartFromTypeAsync(name, id);

await _notifier.SuccessAsync(H["The \"{0}\" part has been removed.", name]);
await _notifier.SuccessAsync(H["The \"{0}\" part has been removed.", name]);
}
catch
{
await _notifier.ErrorAsync(H["The \"{0}\" part cannot be removed.", name]);
}

return RedirectToAction(nameof(Edit), new { id });
}
Expand All @@ -440,8 +454,8 @@ public async Task<ActionResult> ListParts()

return View(new ListContentPartsViewModel
{
// only user-defined parts (not code as they are not configurable)
Parts = await _contentDefinitionService.GetPartsAsync(true/*metadataPartsOnly*/)
// Only user-defined parts (not code as they are not configurable).
Parts = await _contentDefinitionService.GetPartsAsync(metadataPartsOnly: true)
});
}

Expand Down
Loading