Generic user_bottom wiki block

This commit is contained in:
2026-05-20 16:02:26 +02:00
parent 3feea8df81
commit 4c8faf40ec
5 changed files with 49 additions and 32 deletions
+19 -24
View File
@@ -156,9 +156,9 @@ func TestMergeManagedContentPreservesUserTopAndBottomSections(t *testing.T) {
`<p>User-written overview.</p>`, `<p>User-written overview.</p>`,
`<!-- sow-topdata-wiki:manual:end id="user_top" -->`, `<!-- sow-topdata-wiki:manual:end id="user_top" -->`,
`<p>Old generated body.</p>`, `<p>Old generated body.</p>`,
`<!-- sow-topdata-wiki:manual:start id="notes" -->`, `<!-- sow-topdata-wiki:manual:start id="user_bottom" -->`,
`<h2>Notes</h2><p>User note.</p>`, `<p>User-written bottom content.</p>`,
`<!-- sow-topdata-wiki:manual:end id="notes" -->`, `<!-- sow-topdata-wiki:manual:end id="user_bottom" -->`,
`<!-- sow-topdata-wiki:managed:end -->`, `<!-- sow-topdata-wiki:managed:end -->`,
}, "\n") }, "\n")
generated := strings.Join([]string{ generated := strings.Join([]string{
@@ -169,16 +169,16 @@ func TestMergeManagedContentPreservesUserTopAndBottomSections(t *testing.T) {
`<p></p>`, `<p></p>`,
`<!-- sow-topdata-wiki:manual:end id="user_top" -->`, `<!-- sow-topdata-wiki:manual:end id="user_top" -->`,
`<p>New generated body.</p>`, `<p>New generated body.</p>`,
`<!-- sow-topdata-wiki:manual:start id="notes" -->`, `<!-- sow-topdata-wiki:manual:start id="user_bottom" -->`,
`<h2>Notes</h2><p></p>`, `<p></p>`,
`<!-- sow-topdata-wiki:manual:end id="notes" -->`, `<!-- sow-topdata-wiki:manual:end id="user_bottom" -->`,
`<!-- sow-topdata-wiki:managed:end -->`, `<!-- sow-topdata-wiki:managed:end -->`,
}, "\n") }, "\n")
merged := mergeManagedContent(existing, generated) merged := mergeManagedContent(existing, generated)
for _, expected := range []string{ for _, expected := range []string{
"<p>User-written overview.</p>", "<p>User-written overview.</p>",
"<h2>Notes</h2><p>User note.</p>", "<p>User-written bottom content.</p>",
"<p>New generated body.</p>", "<p>New generated body.</p>",
} { } {
if !strings.Contains(merged, expected) { if !strings.Contains(merged, expected) {
@@ -393,10 +393,9 @@ func TestDeployWikiAdoptsExistingNodeBBPageWhenManifestIsMissingWithoutCreate(t
<h1>Acolyte</h1> <h1>Acolyte</h1>
<p>Generated acolyte page</p> <p>Generated acolyte page</p>
<!-- sow-topdata-wiki:managed:end --> <!-- sow-topdata-wiki:managed:end -->
<!-- sow-topdata-wiki:manual:start id="notes" --> <!-- sow-topdata-wiki:manual:start id="user_bottom" -->
<h2>Notes</h2>
<p></p> <p></p>
<!-- sow-topdata-wiki:manual:end id="notes" --> <!-- sow-topdata-wiki:manual:end id="user_bottom" -->
` `
if err := os.WriteFile(filepath.Join(sourceDir, "classes", "acolyte.html"), []byte(generated), 0644); err != nil { if err := os.WriteFile(filepath.Join(sourceDir, "classes", "acolyte.html"), []byte(generated), 0644); err != nil {
t.Fatalf("write source page: %v", err) t.Fatalf("write source page: %v", err)
@@ -406,10 +405,9 @@ func TestDeployWikiAdoptsExistingNodeBBPageWhenManifestIsMissingWithoutCreate(t
<h1>Acolyte</h1> <h1>Acolyte</h1>
<p>Old acolyte page</p> <p>Old acolyte page</p>
<!-- sow-topdata-wiki:managed:end --> <!-- sow-topdata-wiki:managed:end -->
<!-- sow-topdata-wiki:manual:start id="notes" --> <!-- sow-topdata-wiki:manual:start id="user_bottom" -->
<h2>Notes</h2>
<p>Keep this remote note.</p> <p>Keep this remote note.</p>
<!-- sow-topdata-wiki:manual:end id="notes" --> <!-- sow-topdata-wiki:manual:end id="user_bottom" -->
` `
createCalls := 0 createCalls := 0
@@ -500,14 +498,9 @@ func TestDeployWikiMergesHTMLManagedAndManualRegions(t *testing.T) {
<h1>Athletics</h1> <h1>Athletics</h1>
<p>Generated athletics page</p> <p>Generated athletics page</p>
<!-- sow-topdata-wiki:managed:end --> <!-- sow-topdata-wiki:managed:end -->
<!-- sow-topdata-wiki:manual:start id="notes" --> <!-- sow-topdata-wiki:manual:start id="user_bottom" -->
<h2>Notes</h2>
<p></p> <p></p>
<!-- sow-topdata-wiki:manual:end id="notes" --> <!-- sow-topdata-wiki:manual:end id="user_bottom" -->
<!-- sow-topdata-wiki:manual:start id="see_also" -->
<h2>See Also</h2>
<p></p>
<!-- sow-topdata-wiki:manual:end id="see_also" -->
` `
if err := os.WriteFile(filepath.Join(sourceDir, "skills", "athletics.html"), []byte(generated), 0644); err != nil { if err := os.WriteFile(filepath.Join(sourceDir, "skills", "athletics.html"), []byte(generated), 0644); err != nil {
t.Fatalf("write source page: %v", err) t.Fatalf("write source page: %v", err)
@@ -517,10 +510,9 @@ func TestDeployWikiMergesHTMLManagedAndManualRegions(t *testing.T) {
<h1>Athletics</h1> <h1>Athletics</h1>
<p>Old generated text</p> <p>Old generated text</p>
<!-- sow-topdata-wiki:managed:end --> <!-- sow-topdata-wiki:managed:end -->
<!-- sow-topdata-wiki:manual:start id="notes" --> <!-- sow-topdata-wiki:manual:start id="user_bottom" -->
<h2>Notes</h2>
<p>Keep this human note.</p> <p>Keep this human note.</p>
<!-- sow-topdata-wiki:manual:end id="notes" --> <!-- sow-topdata-wiki:manual:end id="user_bottom" -->
` `
manifestPath := filepath.Join(root, "deploy-manifest.json") manifestPath := filepath.Join(root, "deploy-manifest.json")
if err := saveDeployManifest(manifestPath, wikiDeployManifest{ if err := saveDeployManifest(manifestPath, wikiDeployManifest{
@@ -572,9 +564,12 @@ func TestDeployWikiMergesHTMLManagedAndManualRegions(t *testing.T) {
if result.Updated != 1 { if result.Updated != 1 {
t.Fatalf("expected one update, got %#v", result) t.Fatalf("expected one update, got %#v", result)
} }
if !containsAll(updated, "<p>Generated athletics page</p>", "<p>Keep this human note.</p>", `manual:start id="see_also"`) { if !containsAll(updated, "<p>Generated athletics page</p>", "<p>Keep this human note.</p>", `manual:start id="user_bottom"`) {
t.Fatalf("expected update to replace managed HTML and preserve/bootstrap manual regions:\n%s", updated) t.Fatalf("expected update to replace managed HTML and preserve/bootstrap manual regions:\n%s", updated)
} }
if strings.Contains(updated, `manual:start id="notes"`) || strings.Contains(updated, `manual:start id="see_also"`) {
t.Fatalf("expected update to omit legacy split bottom manual regions:\n%s", updated)
}
} }
func TestDeployWikiUpdateAcquiresWestgateWikiEditLock(t *testing.T) { func TestDeployWikiUpdateAcquiresWestgateWikiEditLock(t *testing.T) {
+1 -1
View File
@@ -246,7 +246,7 @@ func loadWikiManualSections(p *project.Project) []wikiManualSection {
switch section.ID { switch section.ID {
case "user_top": case "user_top":
section.Alias = "UserTopSection" section.Alias = "UserTopSection"
case "notes": case "user_bottom":
section.Alias = "UserBottomSection" section.Alias = "UserBottomSection"
} }
} }
+27 -4
View File
@@ -59,8 +59,11 @@ func TestBuildNativeGeneratesAndSkipsWikiPages(t *testing.T) {
if strings.Contains(text, "[//]: #") || strings.Contains(text, "<WRAP>") { if strings.Contains(text, "[//]: #") || strings.Contains(text, "<WRAP>") {
t.Fatalf("expected generated HTML to omit DokuWiki-era syntax:\n%s", text) t.Fatalf("expected generated HTML to omit DokuWiki-era syntax:\n%s", text)
} }
if !strings.Contains(text, `<!-- sow-topdata-wiki:manual:start id="notes" -->`) || !strings.Contains(text, "<h2>See Also</h2>") { if !strings.Contains(text, `<!-- sow-topdata-wiki:manual:start id="user_bottom" -->`) {
t.Fatalf("expected generated page to include manual section placeholders:\n%s", text) t.Fatalf("expected generated page to include user_bottom manual section placeholder:\n%s", text)
}
if strings.Contains(text, `manual:start id="notes"`) || strings.Contains(text, `manual:start id="see_also"`) || strings.Contains(text, "<h2>See Also</h2>") {
t.Fatalf("expected generated page to omit legacy split bottom manual sections:\n%s", text)
} }
statusPath := filepath.Join(root, ".cache", "wiki", "pages", "meta", "wikistatus.html") statusPath := filepath.Join(root, ".cache", "wiki", "pages", "meta", "wikistatus.html")
statusRaw, err := os.ReadFile(statusPath) statusRaw, err := os.ReadFile(statusPath)
@@ -130,6 +133,26 @@ func countGeneratedWikiHTMLFiles(t *testing.T, root string) int {
return count return count
} }
func TestDefaultWikiManualSectionsUseSingleUserBottomBlock(t *testing.T) {
sections := defaultWikiManualSections()
if len(sections) != 2 {
t.Fatalf("expected top and bottom manual sections only, got %#v", sections)
}
expected := map[string]string{
"user_top": "UserTopSection",
"user_bottom": "UserBottomSection",
}
for _, section := range sections {
alias, ok := expected[section.ID]
if !ok {
t.Fatalf("unexpected default manual section %#v", section)
}
if section.Alias != alias {
t.Fatalf("expected alias %q for %q, got %q", alias, section.ID, section.Alias)
}
}
}
func TestWikiClassNamePrefersFullNameInsteadOfShortCode(t *testing.T) { func TestWikiClassNamePrefersFullNameInsteadOfShortCode(t *testing.T) {
ctx := &wikiContext{} ctx := &wikiContext{}
got := ctx.resolveRowName("classes", map[string]any{ got := ctx.resolveRowName("classes", map[string]any{
@@ -158,7 +181,7 @@ func TestWikiTemplateRendersFieldsFormattersAndPreservedTopSection(t *testing.T)
}, },
ManualSections: []wikiManualSection{ ManualSections: []wikiManualSection{
{ID: "user_top", Alias: "UserTopSection", InitialHTML: "<p></p>"}, {ID: "user_top", Alias: "UserTopSection", InitialHTML: "<p></p>"},
{ID: "notes", Alias: "UserBottomSection", InitialHTML: "<h2>Notes</h2><p></p>"}, {ID: "user_bottom", Alias: "UserBottomSection", InitialHTML: "<p></p>"},
}, },
} }
@@ -181,7 +204,7 @@ func TestWikiTemplateRendersFieldsFormattersAndPreservedTopSection(t *testing.T)
"<p>Skill Points: 4</p>", "<p>Skill Points: 4</p>",
"This is a new class!", "This is a new class!",
"<p>Acolyte description.</p>", "<p>Acolyte description.</p>",
`<!-- sow-topdata-wiki:manual:start id="notes" -->`, `<!-- sow-topdata-wiki:manual:start id="user_bottom" -->`,
} { } {
if !strings.Contains(got, expected) { if !strings.Contains(got, expected) {
t.Fatalf("expected %q in rendered template:\n%s", expected, got) t.Fatalf("expected %q in rendered template:\n%s", expected, got)
+1 -2
View File
@@ -49,7 +49,6 @@ func normalizePreservedSectionBodies(content string) string {
func defaultWikiManualSections() []wikiManualSection { func defaultWikiManualSections() []wikiManualSection {
return []wikiManualSection{ return []wikiManualSection{
{ID: "user_top", Alias: "UserTopSection", Heading: "", InitialHTML: "<p></p>"}, {ID: "user_top", Alias: "UserTopSection", Heading: "", InitialHTML: "<p></p>"},
{ID: "notes", Alias: "UserBottomSection", Heading: "Notes", InitialHTML: "<h2>Notes</h2><p></p>"}, {ID: "user_bottom", Alias: "UserBottomSection", Heading: "", InitialHTML: "<p></p>"},
{ID: "see_also", Heading: "See Also", InitialHTML: "<h2>See Also</h2><p></p>"},
} }
} }
+1 -1
View File
@@ -158,7 +158,7 @@ func wikiManualSectionForAlias(sections []wikiManualSection, alias string) (wiki
} }
case "UserBottomSection": case "UserBottomSection":
for _, section := range sections { for _, section := range sections {
if section.ID == "notes" { if section.ID == "user_bottom" {
return section, true return section, true
} }
} }