From 982e45a56edf898780905f7db6eb47c2ddd33119 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 4 Jul 2026 01:20:29 -0500 Subject: [PATCH 1/5] fix: support radio inputs in admin system config form The system config form JS (config.ts) only mapped checkbox, text, textarea, and datetime-local elements. The fork landing_page.tmpl uses radio inputs for the Mode field, so fillFromSystemConfig() hit unsupportedElement() and threw, aborting all JS init on the admin settings page. Add radio handling in both directions: fill checks the option whose value matches the config value; collect returns the checked option's value and skips/nulls unchecked radios so a group resolves to exactly one value. Adds a radio-group test case. --- CHANGELOG.md | 1 + web_src/js/features/admin/config.test.ts | 7 +++++++ web_src/js/features/admin/config.ts | 13 +++++++++++++ 3 files changed, 21 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0aea9e753f..3e69540f09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,7 @@ - Cherry-pick upstream v1.26.4: walk git log context error handling — regression fix (#38185) ### Fixed +- Admin config form: radio inputs (e.g. instance landing page Mode) no longer throw "Unsupported config form value mapping", which had aborted all JS init on the admin settings page - PR check: platform detection now queries metadata API instead of removed manifest.xml - Cherry-pick upstream v1.26.2: handle empty pull request files view to allow reviews (#37783) - Cherry-pick upstream v1.26.2: fix "run as root" check with snap container detection (#37622) diff --git a/web_src/js/features/admin/config.test.ts b/web_src/js/features/admin/config.test.ts index b8468610ca..b7763ee6b7 100644 --- a/web_src/js/features/admin/config.test.ts +++ b/web_src/js/features/admin/config.test.ts @@ -21,6 +21,12 @@ test('ConfigFormValueMapper', () => { + + + + + + `; @@ -44,5 +50,6 @@ test('ConfigFormValueMapper', () => { 'k-flipped-true': 'true', 'repository.open-with.editor-apps': '[{"DisplayName":"a","OpenURL":"b"}]', // TODO: OPEN-WITH-EDITOR-APP-JSON: it must match backend 'struct': '{"SubBoolean":true,"SubTimestamp":123456780,"OtherKey":"other-value","NewKey":"new-value"}', + 'landing': '{"Mode":"explore"}', }); }); diff --git a/web_src/js/features/admin/config.ts b/web_src/js/features/admin/config.ts index 96c7dcf84b..02bced6fa2 100644 --- a/web_src/js/features/admin/config.ts +++ b/web_src/js/features/admin/config.ts @@ -99,6 +99,9 @@ export class ConfigFormValueMapper { if (el.matches('[type="checkbox"]')) { if (valType !== 'boolean') requireExplicitValueType(el); el.checked = Boolean(val ?? el.checked); + } else if (el.matches('[type="radio"]')) { + // a radio group shares one name; check only the option whose value equals the config value + el.checked = el.value === String(val); } else if (el.matches('[type="datetime-local"]')) { if (valType !== 'timestamp') requireExplicitValueType(el); if (val) el.value = toDatetimeLocalValue(val); @@ -120,6 +123,9 @@ export class ConfigFormValueMapper { // it needs to iterate the "namedElems" to find all the checkboxes with the same name and collect values accordingly, // and set the namedElems[matchedIdx] to null to avoid duplicate processing. val = collectCheckboxBooleanValue(el); + } else if (el.matches('[type="radio"]')) { + // only the checked radio of a group reaches here (callers skip unchecked ones); its value is the selection + val = el.value; } else if (el.matches('[type="datetime-local"]')) { if (valType !== 'timestamp') requireExplicitValueType(el); val = Math.floor(new Date(el.value).getTime() / 1000) ?? 0; // NaN is fine to JSON.stringify, it becomes null. @@ -139,6 +145,12 @@ export class ConfigFormValueMapper { if (!el) continue; const subKey = extractElemConfigSubKey(el, dynKey); if (!subKey) continue; // if not match, skip + // a radio group has N elements sharing the same name; only the checked one carries the value. + // drop the unchecked ones so they neither overwrite the selection here nor leak into the fallback loop. + if (el.matches('[type="radio"]') && !el.checked) { + namedElems[idx] = null; + continue; + } cfgVal[subKey] = this.collectConfigValueFromElement(el); namedElems[idx] = null; } @@ -194,6 +206,7 @@ export class ConfigFormValueMapper { // "foo.enabled" => "true" for (const el of namedElems) { if (!el) continue; + if (el.matches('[type="radio"]') && !el.checked) continue; // skip unchecked radios of a top-level group const dynKey = el.name; const newVal = this.collectConfigValueFromElement(el); formData.append('key', dynKey); -- 2.52.0 From efb04334123e8afdcd6afad8310d36b3426f36c1 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 4 Jul 2026 13:15:10 -0500 Subject: [PATCH 2/5] fix: preserve server-rendered radio default when config value is empty LandingPageType.Mode defaults to "" (Go zero value), and the template renders the home radio as checked for an empty Mode. The initial radio fill would evaluate home.checked = ("home" === "") = false, unchecking the default on a fresh install. Skip assignment when the config value is empty so the server-rendered selection is preserved. Adds a test for the empty-value case. --- web_src/js/features/admin/config.test.ts | 6 ++++++ web_src/js/features/admin/config.ts | 5 +++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/web_src/js/features/admin/config.test.ts b/web_src/js/features/admin/config.test.ts index b7763ee6b7..d633aa9502 100644 --- a/web_src/js/features/admin/config.test.ts +++ b/web_src/js/features/admin/config.test.ts @@ -27,6 +27,11 @@ test('ConfigFormValueMapper', () => { + + + + + `; @@ -51,5 +56,6 @@ test('ConfigFormValueMapper', () => { 'repository.open-with.editor-apps': '[{"DisplayName":"a","OpenURL":"b"}]', // TODO: OPEN-WITH-EDITOR-APP-JSON: it must match backend 'struct': '{"SubBoolean":true,"SubTimestamp":123456780,"OtherKey":"other-value","NewKey":"new-value"}', 'landing': '{"Mode":"explore"}', + 'landingDefault': '{"Mode":"home"}', }); }); diff --git a/web_src/js/features/admin/config.ts b/web_src/js/features/admin/config.ts index 02bced6fa2..64cba73213 100644 --- a/web_src/js/features/admin/config.ts +++ b/web_src/js/features/admin/config.ts @@ -100,8 +100,9 @@ export class ConfigFormValueMapper { if (valType !== 'boolean') requireExplicitValueType(el); el.checked = Boolean(val ?? el.checked); } else if (el.matches('[type="radio"]')) { - // a radio group shares one name; check only the option whose value equals the config value - el.checked = el.value === String(val); + // a radio group shares one name; check only the option whose value equals the config value. + // when the value is empty (unset), leave the server-rendered default selection untouched. + if (String(val) !== '') el.checked = el.value === String(val); } else if (el.matches('[type="datetime-local"]')) { if (valType !== 'timestamp') requireExplicitValueType(el); if (val) el.value = toDatetimeLocalValue(val); -- 2.52.0 From b252e9569fd1231eec521fb206bc8bc44368f583 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 4 Jul 2026 13:36:47 -0500 Subject: [PATCH 3/5] ci: allow fix/patch branches to target main and guard missing manifest Branch policy in pr-check.yml only allowed fix/* and patch/* to target dev/rc, blocking fix/* PRs to main despite the documented policy. Allow fix/* -> main and patch/* -> main. Also guard the Detect platform step for a missing .mokogitea/manifest.xml (removed in favor of the metadata API) so it no longer aborts the Validate PR job under set -e. --- .mokogitea/workflows/pr-check.yml | 23 ++++++++++++++--------- CHANGELOG.md | 2 ++ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/.mokogitea/workflows/pr-check.yml b/.mokogitea/workflows/pr-check.yml index c834bf5f8b..a789ecca58 100644 --- a/.mokogitea/workflows/pr-check.yml +++ b/.mokogitea/workflows/pr-check.yml @@ -47,15 +47,15 @@ jobs: fi ;; fix/*|bugfix/*) - if [ "$BASE" != "dev" ]; then + if [ "$BASE" != "dev" ] && [ "$BASE" != "main" ]; then ALLOWED=false - REASON="Fix branches must target 'dev', not '${BASE}'" + REASON="Fix branches must target 'dev' or 'main', not '${BASE}'" fi ;; patch/*) - if [ "$BASE" != "dev" ] && [ "$BASE" != "rc" ]; then + if [ "$BASE" != "dev" ] && [ "$BASE" != "rc" ] && [ "$BASE" != "main" ]; then ALLOWED=false - REASON="Patch branches must target 'dev' or 'rc', not '${BASE}'" + REASON="Patch branches must target 'dev', 'rc', or 'main', not '${BASE}'" fi ;; hotfix/*) @@ -86,7 +86,8 @@ jobs: echo "" >> $GITHUB_STEP_SUMMARY echo "### Allowed merge paths:" >> $GITHUB_STEP_SUMMARY echo "- \`feature/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY - echo "- \`fix/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY + echo "- \`fix/*\` → \`dev\` or \`main\`" >> $GITHUB_STEP_SUMMARY + echo "- \`patch/*\` → \`dev\`, \`rc\`, or \`main\`" >> $GITHUB_STEP_SUMMARY echo "- \`hotfix/*\` → \`dev\` or \`main\`" >> $GITHUB_STEP_SUMMARY echo "- \`dev\` → \`main\`" >> $GITHUB_STEP_SUMMARY echo "- \`rc/*\` → \`main\`" >> $GITHUB_STEP_SUMMARY @@ -147,10 +148,14 @@ jobs: - name: Detect platform id: platform run: | - # Read platform from XML manifest ( tag) or plain text fallback - PLATFORM=$(sed -n 's/.*\([^<]*\)<\/platform>.*/\1/p' .mokogitea/manifest.xml 2>/dev/null | head -1) - [ -z "$PLATFORM" ] && PLATFORM=$(cat .mokogitea/manifest.xml 2>/dev/null | tr -d '[:space:]') - [ -z "$PLATFORM" ] && PLATFORM="generic" + # Read platform from XML manifest ( tag) if present; otherwise default to generic. + # manifest.xml was removed in favor of the metadata API, so guard for its absence to avoid + # aborting under `set -e` when the file is missing. + PLATFORM="generic" + if [ -f .mokogitea/manifest.xml ]; then + DETECTED=$(sed -n 's/.*\([^<]*\)<\/platform>.*/\1/p' .mokogitea/manifest.xml | head -1) + [ -n "$DETECTED" ] && PLATFORM="$DETECTED" + fi echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT" - name: Setup PHP diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e69540f09..7bbb61c6ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -58,6 +58,8 @@ ### Fixed - Admin config form: radio inputs (e.g. instance landing page Mode) no longer throw "Unsupported config form value mapping", which had aborted all JS init on the admin settings page +- PR check branch policy: allow `fix/*` → `main` and `patch/*` → `main` to match documented policy (was rejecting fix/patch PRs to main) +- PR check platform detection: guard for missing `.mokogitea/manifest.xml` so the Validate PR job no longer aborts under `set -e` (manifest replaced by metadata API) - PR check: platform detection now queries metadata API instead of removed manifest.xml - Cherry-pick upstream v1.26.2: handle empty pull request files view to allow reviews (#37783) - Cherry-pick upstream v1.26.2: fix "run as root" check with snap container detection (#37622) -- 2.52.0 From fc234bc91170a410fcecf611c3694d049a4a5241 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 4 Jul 2026 13:46:35 -0500 Subject: [PATCH 4/5] fix: remove dangling mcp-mokogitea-api submodule gitlink The tree carried a gitlink at mcp-mokogitea-api (mode 160000) with no .gitmodules entry, so git submodule update --init --recursive failed with exit 128 at checkout, breaking every PR build/release job. mcp-mokogitea-api is a separate repo, not a submodule; remove the gitlink from the index (keeping the local working-tree clone) and gitignore the path so it can't be re-added. --- .gitignore | 3 +++ CHANGELOG.md | 1 + mcp-mokogitea-api | 1 - 3 files changed, 4 insertions(+), 1 deletion(-) delete mode 160000 mcp-mokogitea-api diff --git a/.gitignore b/.gitignore index 76a7578646..d2f1993ee7 100644 --- a/.gitignore +++ b/.gitignore @@ -120,3 +120,6 @@ prime/ # A Makefile for custom make targets Makefile.local + +# Local clone of the MCP server (separate repo, not a submodule of this project) +/mcp-mokogitea-api/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bbb61c6ef..422c646056 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -60,6 +60,7 @@ - Admin config form: radio inputs (e.g. instance landing page Mode) no longer throw "Unsupported config form value mapping", which had aborted all JS init on the admin settings page - PR check branch policy: allow `fix/*` → `main` and `patch/*` → `main` to match documented policy (was rejecting fix/patch PRs to main) - PR check platform detection: guard for missing `.mokogitea/manifest.xml` so the Validate PR job no longer aborts under `set -e` (manifest replaced by metadata API) +- Remove dangling `mcp-mokogitea-api` submodule gitlink (no `.gitmodules` entry) that broke `submodule update --init` at checkout, failing all PR build/release jobs; ignore the local clone path - PR check: platform detection now queries metadata API instead of removed manifest.xml - Cherry-pick upstream v1.26.2: handle empty pull request files view to allow reviews (#37783) - Cherry-pick upstream v1.26.2: fix "run as root" check with snap container detection (#37622) diff --git a/mcp-mokogitea-api b/mcp-mokogitea-api deleted file mode 160000 index dbaf91546e..0000000000 --- a/mcp-mokogitea-api +++ /dev/null @@ -1 +0,0 @@ -Subproject commit dbaf91546e0fb44614cf8d914b7a78e679dc1efe -- 2.52.0 From aea43708456bc41de5e49c7f6fef5dd9fef16918 Mon Sep 17 00:00:00 2001 From: Jonathan Miller Date: Sat, 4 Jul 2026 13:53:15 -0500 Subject: [PATCH 5/5] ci: no-op PR RC Release when updates.xml is absent The RC release workflow drives a Joomla-style updates.xml update stream. On a generic repo with no updates.xml, the Determine RC version step ran sed on a missing file and aborted under set -e (exit 2). Detect updates.xml presence and gate the update-stream steps (edit/create-release/commit) on it so the job succeeds and no-ops when there is nothing to package. --- .mokogitea/workflows/custom/pr-rc-release.yml | 15 ++++++++++++--- CHANGELOG.md | 1 + 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/.mokogitea/workflows/custom/pr-rc-release.yml b/.mokogitea/workflows/custom/pr-rc-release.yml index 998a25a7f7..f6b9f905f6 100644 --- a/.mokogitea/workflows/custom/pr-rc-release.yml +++ b/.mokogitea/workflows/custom/pr-rc-release.yml @@ -47,6 +47,15 @@ jobs: env: PR_NUMBER: ${{ github.event.pull_request.number }} run: | + # This RC flow drives a Joomla-style update stream (updates.xml). Repos that don't ship + # one (e.g. generic Go/TS) have nothing to package here, so no-op cleanly instead of + # aborting under `set -e` when the file is absent. + if [ ! -f updates.xml ]; then + echo "has_updates=false" >> "$GITHUB_OUTPUT" + echo "No updates.xml in this repo — skipping RC update-stream packaging" + exit 0 + fi + echo "has_updates=true" >> "$GITHUB_OUTPUT" BASE_VERSION=$(sed -n 's/.*\(.*\)<\/version>.*/\1/p' updates.xml | head -1) [ -z "$BASE_VERSION" ] && BASE_VERSION="04.00.00" RC_VERSION="${BASE_VERSION}-rc.${PR_NUMBER}" @@ -56,7 +65,7 @@ jobs: echo "RC version: $RC_VERSION (tag: $RC_TAG)" - name: Update updates.xml RC channel - if: steps.guard.outputs.skip != 'true' + if: steps.guard.outputs.skip != 'true' && steps.version.outputs.has_updates == 'true' env: RC_VERSION: ${{ steps.version.outputs.version }} RC_TAG: ${{ steps.version.outputs.tag }} @@ -106,7 +115,7 @@ jobs: PYEOF - name: Create RC release - if: steps.guard.outputs.skip != 'true' + if: steps.guard.outputs.skip != 'true' && steps.version.outputs.has_updates == 'true' env: GITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }} RC_TAG: ${{ steps.version.outputs.tag }} @@ -153,7 +162,7 @@ jobs: PYEOF - name: Commit updates.xml - if: steps.guard.outputs.skip != 'true' + if: steps.guard.outputs.skip != 'true' && steps.version.outputs.has_updates == 'true' env: GITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }} HEAD_REF: ${{ github.event.pull_request.head.ref }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 422c646056..64ac781fde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -61,6 +61,7 @@ - PR check branch policy: allow `fix/*` → `main` and `patch/*` → `main` to match documented policy (was rejecting fix/patch PRs to main) - PR check platform detection: guard for missing `.mokogitea/manifest.xml` so the Validate PR job no longer aborts under `set -e` (manifest replaced by metadata API) - Remove dangling `mcp-mokogitea-api` submodule gitlink (no `.gitmodules` entry) that broke `submodule update --init` at checkout, failing all PR build/release jobs; ignore the local clone path +- PR RC Release workflow: no-op cleanly when `updates.xml` is absent (generic repos) instead of aborting the "Determine RC version" step under `set -e` - PR check: platform detection now queries metadata API instead of removed manifest.xml - Cherry-pick upstream v1.26.2: handle empty pull request files view to allow reviews (#37783) - Cherry-pick upstream v1.26.2: fix "run as root" check with snap container detection (#37622) -- 2.52.0