Feature: Let custom modules extend the panel via manifests without editing stock PB sources by mcawful · Pull Request #3720 · PhantomBot/PhantomBot · GitHub
Skip to content

Feature: Let custom modules extend the panel via manifests without editing stock PB sources#3720

Merged
gmt2001 merged 53 commits into
PhantomBot:masterfrom
mcawful:feature/custom-module-enhancement
May 17, 2026
Merged

Feature: Let custom modules extend the panel via manifests without editing stock PB sources#3720
gmt2001 merged 53 commits into
PhantomBot:masterfrom
mcawful:feature/custom-module-enhancement

Conversation

@mcawful

@mcawful mcawful commented May 17, 2026

Copy link
Copy Markdown
Contributor

Brief description of the intended change

Purpose: Give custom and community modules a supported way to extend the web panelsidebar links in the extra, alerts, giveaways, or audio submenus (via each nav item’s section), Games cards, and optional settings / “more info” UI—by shipping a manifest.json next to their usual Rhino scripts and panel pages, instead of editing PhantomBot’s stock panel sources. The bot collects, validates, and serves those manifests to the browser so installs (including Docker with a data volume) can pick up panel contributions safely after a refresh or reload.


New files

PhantomBot/source/com/mcawful/CustomPanelManifestCollector.java

  • Scan web/panel/custom/**/manifest.json, validate and merge nav / cards, warn on bad input — the panel must not trust raw manifests; this is the single server-side gate for schema, safety rules, deduplication, and merge order before any JSON is served.

PhantomBot/source/com/mcawful/CustomPanelManifestCache.java

  • Memoize merged manifest JSON (and related cache metadata) for the panel endpoint — manifest scans can touch many files; caching keeps panel loads and polling cheap and enables 304 Not Modified responses.

PhantomBot/javascript-source/core/customScripts.js

  • Hot-scan scripts/custom/ (and lang), !reloadcustom, and initReady replay for newly loaded scripts; invoked silently after manifest fetch from the panel — after a manifest refresh, new or updated Rhino modules should register commands without a full bot restart, and the panel can trigger that path safely.

PhantomBot/resources/web/panel/js/utils/customPanelManifestLoader.js

  • Fetch custom-manifests.json, own window.__pbCustomPanel__, initCustomPanelNav, shared injected CSS (nav, modals, checkbox layout, community card flex row); ensureStylesInjected skips creating a second #pb-custom-panel-styles if one already exists — one place to load merged manifests, share constants/helpers across nav/cards/modals, inject small shared styles (including a stable Games card grid), and avoid duplicate <style> tags on SPA-style navigation.

PhantomBot/resources/web/panel/js/utils/customPanelNav.js

  • Render manifest nav into the sidebar (dividers / sections) — stock index.html cannot list unknown modules; this injects links only into sidebar sections that already expose a submenu mount.

PhantomBot/resources/web/panel/js/utils/customPanelCards.js

  • Render manifest cards on the Games page; toggles, settings, details; add pb-custom-cards-mount on the mount row — community cards need the same enable/disable and settings patterns (along with a new info pattern) as stock games without hand-authored HTML per module.

PhantomBot/resources/web/panel/js/utils/customPanelSettingsModal.js

  • Declarative settings modal (flat fields or sections) and save path — modules should describe settings in JSON instead of shipping bespoke modal HTML/JS for every field shape we support.

PhantomBot/resources/web/panel/js/utils/customPanelDetailsModal.js

  • Read-only details modal from manifest content — authors need a supported “about this module” surface tied to the same manifest as nav/cards.

PhantomBot/docs/guides/content/developerdocs/custommodules.md

  • Developer doc for manifest.json, paths, and behavior overview — contributors need a canonical contract (paths, section values, field types) separate from scattered README fragments.

PhantomBot/docs/guides/content/moduleguides/addingcustommodules.md

  • Installer-oriented module guide (links into developer docs) — installers follow the module guides tree first; this points them at manifest-based development when they outgrow “copy files only.”

Modified files

PhantomBot/source/tv/phantombot/httpserver/HTTPPanelAndYTHandler.java

  • Serve GET /panel/custom-manifests.json from the collector/cache (with 304 when unchanged) — the browser must load merged manifests through the same authenticated panel HTTP stack as the rest of the UI, with cache semantics.

PhantomBot/source/com/gmt2001/PathValidator.java

  • Add isPathUnderExecutionOrDockerWeb (and related checks) so ./web access is valid when custom content lives under the Docker data volume — Docker images symlink web/panel/.../custom into PhantomBot_data; checks that only allow paths under the JAR layout would wrongly 403 legitimate panel files.

PhantomBot/source/tv/phantombot/httpserver/HttpSetupHandler.java

  • Use PathValidator.isPathUnderExecutionOrDockerWeb instead of Reflect.GetExecutionPath() prefix checks for ./web auth paths — web-auth path validation must match where custom panel pages and assets actually live in Docker and bare-metal layouts.

PhantomBot/source/tv/phantombot/httpserver/HTTPOAuthHandler.java

  • Same PathValidator-based web root check as HttpSetupHandler — OAuth-related static ./web fetches use the same path rules; leaving one handler on the old check would be an inconsistent hole.

PhantomBot/source/com/gmt2001/RollbarProvider.java

  • Include com.mcawful in APP_PACKAGES so stack traces from new classes are treated as first-party for Rollbar grouping — new collector/cache code lives under com.mcawful; without this, reports may be misclassified or filtered versus core PhantomBot packages.

PhantomBot/resources/web/panel/index.html

  • Load customPanel*.js in dependency order — the loader must run before modals, nav, and cards; order is part of the public contract between those scripts.

PhantomBot/resources/web/panel/js/index.js

  • Call initCustomPanelNav() after panel websocket auth — nav injection should run only when the panel session is real (socket ready), avoiding empty mounts or duplicate work on the login shell.

PhantomBot/resources/web/panel/js/utils/ajaxLoader.js

  • Delegate [data-folder] clicks on document so dynamically injected custom nav links load pages — manifest nav <a> elements are added after the initial $(function () { ... }) binding; direct binding on [data-folder] never sees them.

PhantomBot/resources/web/panel/pages/games/games.html

  • Add #pb-panel-games-custom-cards mount and injectCustomCards('games', …) — stock Games markup has no mount point for third-party cards; this is the minimal hook that keeps community cards on the same page as built-in games.

PhantomBot/resources/docker-entrypoint.sh

  • mkdir -p for web/panel/pages/custom and web/panel/js/pages/custom under PhantomBot_data — fresh data volumes may lack those directories; the bot should start clean even before the user copies any custom files.

PhantomBot/Dockerfile

  • Stage/move/symlink web/panel/custom, pages/custom, and js/pages/custom into the data volume layout (alongside existing Docker steps) — custom panel files must persist on the volume and be visible under /opt/PhantomBot/web/... at runtime, matching how other mutable web overlays are handled.

PhantomBot/docs/guides/content/developerdocs/toc.json

  • Register the custom modules developer guide in the TOC — the in-panel docs browser builds from TOC JSON; new guides are invisible without an entry.

PhantomBot/docs/guides/content/moduleguides/toc.json

  • Register the adding custom modules guide in the TOC — installers discover guides through the published guide index; same rationale as the developer TOC.

mcawful added 30 commits May 8, 2026 23:34
The OAuth and Setup HTTP handlers previously confined their served-from check to <execution_path>/web, while isValidPathWebAuth already understands assets can also live under the Docker _data volume. This commit factors that dual-root check into a new PathValidator.isPathUnderExecutionOrDockerWeb helper and adopts it in both handlers, so panel assets dropped into PhantomBot_data/web are served correctly in Docker installs.
Walks <execution_path>/web/panel/custom/ (and the Docker _data equivalent), parses every <moduleId>/manifest.json, validates and merges nav and cards entries, and serves the result as a single JSON document for the panel to consume. Invalid manifests are warn-logged and skipped so a single broken module cannot break the panel.

Also adopts PathValidator.isPathUnderExecutionOrDockerWeb in HTTPPanelAndYTHandler for the same Docker _data web root behavior as the OAuth and Setup handlers.
On panel login, fetches /panel/custom-manifests.json and appends the nav entries into the Extra, Alerts, Giveaways, and Audio submenus declared by their manifests. Inserts a one-time 'CUSTOM' divider above the first community-contributed link in each affected section, with styles injected on demand so a panel with no manifests installed renders no extra UI at all.

Switches the [data-folder] click binding in ajaxLoader.js to a delegated handler so the runtime-injected links route correctly through $.loadPage.
Adds a mount point and an injectCustomCards trigger to games.html so the manifest loader's already-shipped card-rendering helpers (buildCardElement, wireCardToggles, wireCardSettings, loadInitialCardStates) actually fire on this page. Cards are appended below the stock cards under a one-time 'Community modules' divider; toggle and cog button render only when the manifest declares scriptPath / settingsFolder respectively.
Fixes an issue caused by the custom cards where disabling/reenabling the custom module doesn't sync with the toggle state of the card (custom card toggle remains in a disabled state regardless of actual state).
Panel-settings-saved when manifest omits wsEvent, pbCustomCardSettingsSaved jQuery + CustomEvent, dispatchBotWsAfterCustomCardSave, $mount.empty(), namespaced toggle handlers, lookupModulesTableValue / modulesDbValueIsEnabled, and initial toggle state from modules.
Collapses four over-engineered manifest features in CustomPanelManifestCollector to keep custom-module authoring straightforward.
Brings the panel-side render/save/details flows in line with the trimmed Java validator contract.
Comment thread resources/web/panel/js/utils/customPanelSettingsModal.js Fixed

@gmt2001 gmt2001 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Prefer using let in all JS var declarations to strictly control scope and prevent global object creation

@gmt2001 gmt2001 self-requested a review May 17, 2026 04:14
Comment thread resources/web/panel/js/utils/customPanelSettingsModal.js Dismissed
Comment thread resources/web/panel/js/utils/customPanelCards.js Outdated
Comment thread source/tv/phantombot/httpserver/HTTPPanelAndYTHandler.java Outdated
Comment thread source/com/mcawful/CustomPanelManifestCollector.java
@Sartharon

Copy link
Copy Markdown
Contributor

@mcawful

mcawful commented May 17, 2026

Copy link
Copy Markdown
Contributor Author

Any plans to integrate permission controls in to this as well with the existing PanelUser concept?

https://github.com/PhantomBot/PhantomBot/tree/master/source/tv/phantombot/panel/PanelUser

I have some slight integration, but I would like to grow it out. If you want, I could look into integrating that with this PR.

@Sartharon

Copy link
Copy Markdown
Contributor

@gmt2001 gmt2001 merged commit 6482021 into PhantomBot:master May 17, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants