feat(ui): add configurable headline and subtitle via env vars#1347
feat(ui): add configurable headline and subtitle via env vars#1347frank-bee wants to merge 1 commit intokagent-dev:mainfrom
Conversation
There was a problem hiding this comment.
Pull request overview
This PR adds support for customizing the UI text via runtime environment variables, allowing deployments to personalize the chat greeting and landing page subtitle without code changes. The implementation reads NEXT_PUBLIC_HEADLINE and NEXT_PUBLIC_SUBTITLE from environment variables and passes them as optional props to the respective components.
Changes:
- Added optional
headlineprop to ChatInterface component for customizable chat greeting text - Added optional
subtitleprop to AgentList component for landing page tagline - Converted
[chatId]/page.tsxfrom client to server component to properly access environment variables - Added
force-dynamicexport to root layout for runtime environment variable support
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| ui/src/components/chat/ChatInterface.tsx | Added optional headline prop with fallback to "Start a conversation" |
| ui/src/components/AgentList.tsx | Added optional subtitle prop displayed below "Agents" heading |
| ui/src/app/page.tsx | Read NEXT_PUBLIC_SUBTITLE env var and pass to AgentList |
| ui/src/app/layout.tsx | Added force-dynamic export for runtime env var access |
| ui/src/app/agents/[namespace]/[name]/chat/page.tsx | Read NEXT_PUBLIC_HEADLINE env var and pass to ChatInterface |
| ui/src/app/agents/[namespace]/[name]/chat/[chatId]/page.tsx | Converted to async server component, read and pass NEXT_PUBLIC_HEADLINE |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| export default function ChatAgentPage({ params }: { params: Promise<{ name: string, namespace: string }> }) { | ||
| const { name, namespace } = use(params); | ||
| return <ChatInterface selectedAgentName={name} selectedNamespace={namespace} />; | ||
| const headline = process.env.NEXT_PUBLIC_HEADLINE; | ||
| return <ChatInterface selectedAgentName={name} selectedNamespace={namespace} headline={headline} />; |
There was a problem hiding this comment.
This page component should be converted to an async server component for consistency with the sibling [chatId]/page.tsx file. The current implementation uses the use() hook which is meant for client components, while the environment variable access pattern suggests server-side rendering is intended.
Convert the function to async and use await params instead of use(params):
export default async function ChatAgentPage({ params }: { params: Promise<{ name: string, namespace: string }> }) {
const { name, namespace } = await params;
const headline = process.env.NEXT_PUBLIC_HEADLINE;
return <ChatInterface selectedAgentName={name} selectedNamespace={namespace} headline={headline} />;
}
Also remove the now-unused use import from 'react'.
There was a problem hiding this comment.
Already done in this PR — both chat/page.tsx and chat/[chatId]/page.tsx are converted to async server components with await params, and the use import is removed.
| export const dynamic = "force-dynamic"; | ||
|
|
There was a problem hiding this comment.
Setting dynamic = "force-dynamic" in the root layout disables static optimization for the entire application, which may have performance implications. Consider setting this only on the specific pages that need runtime environment variable access instead of globally.
For example, you could add export const dynamic = "force-dynamic" to:
ui/src/app/page.tsx(for NEXT_PUBLIC_SUBTITLE)ui/src/app/agents/[namespace]/[name]/chat/page.tsx(for NEXT_PUBLIC_HEADLINE)ui/src/app/agents/[namespace]/[name]/chat/[chatId]/page.tsx(for NEXT_PUBLIC_HEADLINE)
This would allow other pages that don't use these env vars to benefit from static optimization. Note that NEXT_PUBLIC_* env vars are typically available at build time, but if you need them to be configurable at runtime without rebuilding, the current approach or the per-page approach is correct.
| export const dynamic = "force-dynamic"; |
There was a problem hiding this comment.
Intentional. The env vars need to be read at container runtime (not build time) since this is deployed as a Docker image with configurable env vars. force-dynamic is required for that.
Additionally, the sibling PR #1346 (read-only mode) also reads NEXT_PUBLIC_READ_ONLY in the root layout, so force-dynamic needs to be here regardless. Scoping per-page would add boilerplate for negligible gain on a K8s dashboard app.
Add support for customizing the chat headline and landing page subtitle through runtime environment variables, enabling enterprise deployments to personalize the UI without forking. - NEXT_PUBLIC_HEADLINE: replaces "Start a conversation" chat greeting - NEXT_PUBLIC_SUBTITLE: optional tagline below "Agents" on landing page - Add force-dynamic to layout.tsx for runtime env var support - Convert [chatId]/page.tsx to server component for env var access When env vars are not set, everything works exactly as before. Closes kagent-dev#1345 Signed-off-by: Frank Bernhardt <Frank.Bernhardt@quantum-machines.co>
dd7f7eb to
9f34b56
Compare
Summary
NEXT_PUBLIC_HEADLINEenv var to customize the chat greeting text (defaults to "Start a conversation")NEXT_PUBLIC_SUBTITLEenv var to display an optional tagline below the "Agents" heading on the landing pageforce-dynamicexport to layout.tsx to ensure env vars are read at runtime, not baked in at build time[chatId]/page.tsxfrom client component to server component for proper env var accessWhen env vars are not set, everything works exactly as before — zero impact on default deployments.
Environment Variables
NEXT_PUBLIC_HEADLINE"Start a conversation"NEXT_PUBLIC_SUBTITLEFiles Changed
ui/src/app/page.tsx— readNEXT_PUBLIC_SUBTITLE, pass toAgentListui/src/components/AgentList.tsx— accept and render optionalsubtitlepropui/src/components/chat/ChatInterface.tsx— accept optionalheadlinepropui/src/app/agents/[namespace]/[name]/chat/page.tsx— read and passheadlineui/src/app/agents/[namespace]/[name]/chat/[chatId]/page.tsx— convert to server component, read and passheadlineui/src/app/layout.tsx— addforce-dynamicfor runtime env var supportTest plan
NEXT_PUBLIC_HEADLINE="Ask your AI assistant", verify it appears in the chat viewNEXT_PUBLIC_SUBTITLE="Internal AI Platform", verify it appears on the landing pagemake -C ui buildCloses #1345
Related: #1335