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" } } + } }); }