Skip to content

feat(create-a-container): admin-configurable announcement banner#424

Merged
runleveldev merged 2 commits into
mieweb:mainfrom
runleveldev:announcement-banner
Jul 24, 2026
Merged

feat(create-a-container): admin-configurable announcement banner#424
runleveldev merged 2 commits into
mieweb:mainfrom
runleveldev:announcement-banner

Conversation

@runleveldev

Copy link
Copy Markdown
Collaborator

Summary

Adds a deployment-specific announcement banner shown to all users at the top of the app. The message is stored in the existing admin-editable Settings table, so each environment controls its own banner at runtime — no hardcoded URLs in the repo, no env vars, no restart.

Motivating use case: linking users to a companion app whose URL varies per environment, e.g. Try [Ozwell Studio](https://ozwell-studio-launcher.os.mieweb.org).

How it works

Settings (admin sidebar) → Announcement banner → save. The banner renders immediately for all users; clearing the field hides it.

  • New banner_message key in the settings whitelist (PUT/GET /api/v1/settings, stored trimmed)
  • Exposed to everyone via the unauthenticated GET /api/v1/health as banner, mirroring the existing isDev/oidcEnabled flow into useServerInfo(); wrapped in try/catch so a DB hiccup never fails the health check
  • New AppBanner component mounted in AppLayout between the header and main content
  • Supports [text](url) link syntax, parsed client-side into <a> elements (http/https only, no HTML injection) so admin-provided content stays XSS-safe
  • Saving settings invalidates the useServerInfo cache so admins see the change without a reload
  • Admin docs updated (mie-opensource-landing/docs/admins/settings.md)

Testing

  • New integration suite routers/api/v1/__tests__/banner.api.test.js: default-null banner, admin write + unauthenticated exposure via health, non-admin 403, clearing hides it
  • Full server suite passes: 4 suites / 28 tests (24 pre-existing + 4 new)
  • Client tsc -b clean; production build succeeds

Notes

  • useServerInfo caches with staleTime: Infinity, so already-active users pick up banner changes on their next page load
  • The banner currently renders only in the authenticated app shell; it's a one-line addition to AuthLayout if we also want it on the login page

Adds a banner_message setting (admin Settings page) exposed through the
unauthenticated /api/v1/health endpoint and rendered as a strip at the
top of the app shell. Supports [text](url) links, parsed client-side
into anchors (http/https only) so admin-provided content stays XSS-safe.

Lets each deployment announce environment-specific links (e.g. a local
Ozwell Studio launcher) at runtime, without hardcoding URLs in the repo
or requiring a restart.
Copilot AI review requested due to automatic review settings July 23, 2026 19:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds an admin-configurable announcement banner to the create-a-container SPA, stored per-deployment in the existing Settings table and exposed to clients via the unauthenticated /api/v1/health server-info endpoint.

Changes:

  • Add banner_message to admin settings GET/PUT, trimming on write.
  • Extend /api/v1/health to include banner and add client-side useServerInfo() consumption + cache invalidation on settings save.
  • Add a new AppBanner UI component (with [text](url) link parsing) mounted in AppLayout, plus integration tests and admin docs.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
mie-opensource-landing/docs/admins/settings.md Documents the new Announcement Banner setting for admins.
create-a-container/routers/api/v1/settings.js Adds banner_message to the admin settings API payload and persists it trimmed.
create-a-container/routers/api/v1/index.js Exposes banner via unauthenticated /health so the SPA can render it.
create-a-container/routers/api/v1/tests/banner.api.test.js Integration coverage for default banner state, admin write, non-admin denial, and health exposure.
create-a-container/client/src/pages/settings/SettingsPage.tsx Adds banner field to the settings form and invalidates cached server-info on save.
create-a-container/client/src/lib/types.ts Extends AppSettings with bannerMessage.
create-a-container/client/src/lib/auth.ts Extends ServerInfo with banner and exports serverInfoKey used for invalidation.
create-a-container/client/src/app/Banner.tsx New banner component + link parser for [text](url) syntax.
create-a-container/client/src/app/AppLayout.tsx Mounts the banner between the header and main content.

Comment thread create-a-container/client/src/app/Banner.tsx
Comment thread create-a-container/routers/api/v1/index.js Outdated
Comment thread create-a-container/routers/api/v1/index.js Outdated
Comment thread mie-opensource-landing/docs/admins/settings.md
Comment thread create-a-container/client/src/pages/settings/SettingsPage.tsx
Addresses Copilot review on PR mieweb#424: route async handlers through the
project's asyncHandler so any unexpected rejection is forwarded to the
JSON error handler. Express 5 does forward rejected promises natively,
but every other async route here uses the wrapper — stay consistent and
future-proof.
@runleveldev
runleveldev merged commit a4d5043 into mieweb:main Jul 24, 2026
5 of 6 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.

3 participants