From 8d0733f970935b637b27335bff21672a1a0b5e3e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E6=9D=9C=E5=86=A0=E9=AD=81?=
Date: Sun, 6 Sep 2026 09:33:41 +0900
Subject: [PATCH] feat(host): seed a Matrix and a Table field on the About page
Neither composite field type appeared anywhere in the seed data - checked the
full history of all four seed/test-data files, Matrix has never been in any of
them - so the only way to see either one render was to hand-build a
configuration in the admin UI first. That is worth fixing now specifically
because Site no longer declares these types at all: they are flex-fields kernel
built-ins as of 10.0.0-rc.16, and a seeded example is the cheapest way to keep
an eye on the integration.
Adds two fields to the About content type:
- about_highlights (Matrix) with two block types, paragraph and stat, so the
polymorphic-repeater shape is actually exercised rather than a single-block
degenerate case
- about_milestones (Table) with year/event columns
Configurations are built from the kernel's own MatrixConfiguration /
TableConfiguration and InlineFieldDefinition rather than hand-written
dictionaries, so an upstream rename or reshape fails the build here instead of
silently seeding a configuration nothing can read. Values likewise use
MatrixBlockValue / TableRow; ContentManager runs them through the field type's
own Normalize on the way in.
Verified against a real seed run, not just a compile: pointed the host at a
throwaway SQLite database, ran --migrate-database, and read the row back. Both
values are stored in the canonical camelCase wire shape -
[{"blockTypeName":"paragraph","values":{...}}] and [{"values":{...}}] - which
also confirms Normalize and the validation pass ran, since CreateAsync would
have thrown otherwise.
---
.../Data/SiteContentDataSeedContributor.cs | 94 ++++++++++++++++++-
1 file changed, 92 insertions(+), 2 deletions(-)
diff --git a/host/Dignite.Site.Host/Data/SiteContentDataSeedContributor.cs b/host/Dignite.Site.Host/Data/SiteContentDataSeedContributor.cs
index 6c002c8..0ae6371 100644
--- a/host/Dignite.Site.Host/Data/SiteContentDataSeedContributor.cs
+++ b/host/Dignite.Site.Host/Data/SiteContentDataSeedContributor.cs
@@ -4,6 +4,8 @@
using Dignite.Abp.FlexFields;
using Dignite.Abp.FlexFields.CKEditor;
using Dignite.Abp.FlexFields.FileExplorer;
+using Dignite.Abp.FlexFields.Matrix;
+using Dignite.Abp.FlexFields.Table;
using Dignite.FlexFields.Site.Seo;
using Dignite.Site.ContentTypes;
using Dignite.Site.Contents;
@@ -129,15 +131,75 @@ await EnsureContentAsync(
});
}
+ ///
+ /// Carries the two composite field types as well as the scalar ones, so a fresh database has a
+ /// worked example of each: Matrix (a repeatable list of polymorphic blocks) and Table
+ /// (a homogeneous grid over one column schema). Both are flex-fields kernel built-ins as of
+ /// 10.0.0-rc.16; nothing in Site declares them any more, which is precisely why having them in the
+ /// seed is worth the lines - otherwise the only way to see either type render is to hand-build a
+ /// configuration in the admin UI first.
+ ///
+ /// Their configurations are built from the kernel's own MatrixConfiguration/
+ /// TableConfiguration rather than hand-written dictionaries, so a rename or reshape upstream
+ /// breaks this at compile time instead of producing a seed that silently stores an unreadable
+ /// configuration. Values likewise use MatrixBlockValue/TableRow: ContentManager
+ /// runs them through the field type's own Normalize on the way in, which is what turns them
+ /// into the canonical camelCase wire shape every reader downstream expects.
+ ///
+ ///
private async Task SeedAboutAsync(Guid titleFieldId, Guid bodyFieldId)
{
var page = await GetOrCreatePageAsync("about", "About", "/about");
+
+ var highlightsFieldId = await GetOrCreateFieldAsync(
+ "about_highlights", "Highlights", MatrixFieldType.ControlName,
+ "Repeatable blocks shown down the About page - either a paragraph or a headline number.",
+ new MatrixConfiguration
+ {
+ BlockTypes = new List
+ {
+ new()
+ {
+ Name = "paragraph",
+ DisplayName = "Paragraph",
+ Fields = new List
+ {
+ new() { Name = "text", DisplayName = "Text", FieldTypeName = "Text", Required = true }
+ }
+ },
+ new()
+ {
+ Name = "stat",
+ DisplayName = "Statistic",
+ Fields = new List
+ {
+ new() { Name = "value", DisplayName = "Value", FieldTypeName = "Text", Required = true },
+ new() { Name = "label", DisplayName = "Label", FieldTypeName = "Text", Required = true }
+ }
+ }
+ }
+ }.ConfigurationDictionary);
+
+ var milestonesFieldId = await GetOrCreateFieldAsync(
+ "about_milestones", "Milestones", TableFieldType.ControlName,
+ "One row per milestone, all sharing the same columns.",
+ new TableConfiguration
+ {
+ Columns = new List
+ {
+ new() { Name = "year", DisplayName = "Year", FieldTypeName = "Text", Required = true },
+ new() { Name = "event", DisplayName = "Event", FieldTypeName = "Text", Required = true }
+ }
+ }.ConfigurationDictionary);
+
var contentType = await GetOrCreateContentTypeAsync(
page.Id, "about", "About",
new[]
{
Usage(titleFieldId, required: true, showInList: true, order: 0),
- Usage(bodyFieldId, order: 1)
+ Usage(bodyFieldId, order: 1),
+ Usage(highlightsFieldId, order: 2),
+ Usage(milestonesFieldId, order: 3)
});
await EnsureContentAsync(
@@ -146,7 +208,35 @@ await EnsureContentAsync(
{
["title"] = "About Us",
["body"] = "Dignite is a small team building tools for editors and developers to manage " +
- "content together, without either side having to compromise on how they work.
"
+ "content together, without either side having to compromise on how they work.
",
+ ["about_highlights"] = new List
+ {
+ new()
+ {
+ BlockTypeName = "paragraph",
+ Values = new FlexFieldDictionary
+ {
+ ["text"] = "We started Dignite after one too many projects where the CMS decided " +
+ "what the site could be."
+ }
+ },
+ new()
+ {
+ BlockTypeName = "stat",
+ Values = new FlexFieldDictionary { ["value"] = "7", ["label"] = "Field types out of the box" }
+ },
+ new()
+ {
+ BlockTypeName = "stat",
+ Values = new FlexFieldDictionary { ["value"] = "4", ["label"] = "Languages shipped" }
+ }
+ },
+ ["about_milestones"] = new List
+ {
+ new() { Values = new FlexFieldDictionary { ["year"] = "2024", ["event"] = "First internal build" } },
+ new() { Values = new FlexFieldDictionary { ["year"] = "2025", ["event"] = "Flexible fields land" } },
+ new() { Values = new FlexFieldDictionary { ["year"] = "2026", ["event"] = "Composite field types" } }
+ }
});
}