From 559b3e40f9d45ae377275ca32317c9aaafdbdede Mon Sep 17 00:00:00 2001 From: shenlan Date: Sun, 9 Nov 2025 16:51:47 +0800 Subject: [PATCH] Fix marketing product routes for Next.js params (#653) --- .../app/(tenant)/[slug]/mail/compose/page.tsx | 11 +- dashboard/app/(tenant)/[slug]/mail/page.tsx | 10 +- .../(tenant)/[slug]/mail/settings/page.tsx | 11 +- dashboard/app/[slug]/Client.tsx | 2 +- dashboard/app/[slug]/page.tsx | 12 +- .../components/marketing/ProductFeatures.tsx | 142 ++++++++++++++++-- 6 files changed, 167 insertions(+), 21 deletions(-) diff --git a/dashboard/app/(tenant)/[slug]/mail/compose/page.tsx b/dashboard/app/(tenant)/[slug]/mail/compose/page.tsx index bd1a9cf..da125bd 100644 --- a/dashboard/app/(tenant)/[slug]/mail/compose/page.tsx +++ b/dashboard/app/(tenant)/[slug]/mail/compose/page.tsx @@ -2,6 +2,13 @@ export const dynamic = 'error' import ComposeForm from '../../../../components/mail/ComposeForm' -export default function ComposePage({ params }: { params: { slug: string } }) { - return +type PageProps = { + params: Promise<{ + slug: string + }> +} + +export default async function ComposePage({ params }: PageProps) { + const { slug } = await params + return } diff --git a/dashboard/app/(tenant)/[slug]/mail/page.tsx b/dashboard/app/(tenant)/[slug]/mail/page.tsx index 2e041d8..e00a4c7 100644 --- a/dashboard/app/(tenant)/[slug]/mail/page.tsx +++ b/dashboard/app/(tenant)/[slug]/mail/page.tsx @@ -2,7 +2,13 @@ export const dynamic = 'error' import MailDashboard from '../../../components/mail/MailDashboard' -export default function TenantMailPage({ params }: { params: { slug: string } }) { - const { slug } = params +type PageProps = { + params: Promise<{ + slug: string + }> +} + +export default async function TenantMailPage({ params }: PageProps) { + const { slug } = await params return } diff --git a/dashboard/app/(tenant)/[slug]/mail/settings/page.tsx b/dashboard/app/(tenant)/[slug]/mail/settings/page.tsx index 57ca760..aec2671 100644 --- a/dashboard/app/(tenant)/[slug]/mail/settings/page.tsx +++ b/dashboard/app/(tenant)/[slug]/mail/settings/page.tsx @@ -2,6 +2,13 @@ export const dynamic = 'error' import MailSettings from '../../../../components/mail/MailSettings' -export default function MailSettingsPage({ params }: { params: { slug: string } }) { - return +type PageProps = { + params: Promise<{ + slug: string + }> +} + +export default async function MailSettingsPage({ params }: PageProps) { + const { slug } = await params + return } diff --git a/dashboard/app/[slug]/Client.tsx b/dashboard/app/[slug]/Client.tsx index 93e4bf7..34d0c28 100644 --- a/dashboard/app/[slug]/Client.tsx +++ b/dashboard/app/[slug]/Client.tsx @@ -183,7 +183,7 @@ export default function Client({ config }: ClientProps) {
- + diff --git a/dashboard/app/[slug]/page.tsx b/dashboard/app/[slug]/page.tsx index d21e8b4..e23d0b1 100644 --- a/dashboard/app/[slug]/page.tsx +++ b/dashboard/app/[slug]/page.tsx @@ -5,9 +5,9 @@ import Client from './Client' import { PRODUCT_MAP, getAllSlugs } from '@src/products/registry' type PageProps = { - params: { + params: Promise<{ slug: string - } + }> } export async function generateStaticParams() { @@ -15,7 +15,8 @@ export async function generateStaticParams() { } export async function generateMetadata({ params }: PageProps): Promise { - const config = PRODUCT_MAP.get(params.slug) + const { slug } = await params + const config = PRODUCT_MAP.get(slug) if (!config) { return {} @@ -45,8 +46,9 @@ export async function generateMetadata({ params }: PageProps): Promise } } -export default function ProductPage({ params }: PageProps) { - const config = PRODUCT_MAP.get(params.slug) +export default async function ProductPage({ params }: PageProps) { + const { slug } = await params + const config = PRODUCT_MAP.get(slug) if (!config) { notFound() diff --git a/dashboard/components/marketing/ProductFeatures.tsx b/dashboard/components/marketing/ProductFeatures.tsx index 1573441..321bb2a 100644 --- a/dashboard/components/marketing/ProductFeatures.tsx +++ b/dashboard/components/marketing/ProductFeatures.tsx @@ -1,10 +1,37 @@ -import { Activity, Brain, Rocket, Shield } from 'lucide-react' +import type { LucideIcon } from 'lucide-react' +import { + Activity, + BellRing, + Brain, + Cloud, + Coins, + Database, + GitBranch, + Puzzle, + Rocket, + Shield, + ShieldCheck, +} from 'lucide-react' + +import type { ProductConfig } from '@src/products/registry' type ProductFeaturesProps = { + config: ProductConfig lang: 'zh' | 'en' } -const FEATURES = { +type FeatureDefinition = { + title: string + description: string + icon: LucideIcon +} + +type FeatureSet = { + zh: FeatureDefinition[] + en: FeatureDefinition[] +} + +const DEFAULT_FEATURES: FeatureSet = { zh: [ { title: '极速连接', @@ -51,8 +78,109 @@ const FEATURES = { ], } -export default function ProductFeatures({ lang }: ProductFeaturesProps) { - const items = FEATURES[lang] +const FEATURE_LIBRARY: Record = { + xstream: DEFAULT_FEATURES, + xscopehub: { + zh: [ + { + title: '全栈可观测数据', + description: '统一聚合日志、指标与追踪,秒级关联上下游依赖。', + icon: Database, + }, + { + title: 'AI 根因洞察', + description: '基于时间序列与拓扑的智能关联分析,快速定位故障。', + icon: Brain, + }, + { + title: '自动化告警编排', + description: '多渠道告警与自愈策略编排,减少人工值守负担。', + icon: BellRing, + }, + { + title: '生态级集成', + description: '通过 Webhook 与插件体系,与 CI/CD、ITSM 平台无缝联动。', + icon: Puzzle, + }, + ], + en: [ + { + title: 'Full-stack telemetry', + description: 'Unify logs, metrics, and traces with second-level dependency mapping.', + icon: Database, + }, + { + title: 'AI-driven insights', + description: 'Correlate time-series signals with topology to pinpoint root causes fast.', + icon: Brain, + }, + { + title: 'Automated alerting', + description: 'Orchestrate multichannel alerts and auto-remediation runbooks to cut toil.', + icon: BellRing, + }, + { + title: 'Ecosystem integrations', + description: 'Connect to CI/CD and ITSM systems through webhooks and an extensible plugin hub.', + icon: Puzzle, + }, + ], + }, + xcloudflow: { + zh: [ + { + title: '多云蓝图编排', + description: '跨公有云与私有云的资源模型统一建模,一次定义多环境复用。', + icon: Cloud, + }, + { + title: 'GitOps 流水线', + description: '将基础设施交付纳入 Git 审批与回滚流程,自动推进部署。', + icon: GitBranch, + }, + { + title: '策略与合规', + description: '内置策略扫描与准入控制,确保资源变更符合监管要求。', + icon: ShieldCheck, + }, + { + title: '成本可视化', + description: '实时跟踪多云资源使用与成本分摊,辅助优化预算。', + icon: Coins, + }, + ], + en: [ + { + title: 'Multi-cloud blueprints', + description: 'Model infrastructure once and reuse across public and private clouds.', + icon: Cloud, + }, + { + title: 'GitOps pipelines', + description: 'Bring infrastructure delivery into Git reviews with automated rollouts.', + icon: GitBranch, + }, + { + title: 'Policy & compliance', + description: 'Built-in policy checks and admission controls enforce governance at deploy time.', + icon: ShieldCheck, + }, + { + title: 'Cost visibility', + description: 'Track multi-cloud spend and allocations in real time to optimize budgets.', + icon: Coins, + }, + ], + }, +} + +export default function ProductFeatures({ config, lang }: ProductFeaturesProps) { + const featureSet = FEATURE_LIBRARY[config.slug] ?? DEFAULT_FEATURES + const items = featureSet[lang] + const intro = + lang === 'zh' + ? `${config.name} 的核心能力组合,帮助团队快速落地。` + : `Key capabilities from ${config.name} to help your team ship faster.` return (
@@ -61,11 +189,7 @@ export default function ProductFeatures({ lang }: ProductFeaturesProps) {

{lang === 'zh' ? '核心功能' : 'Core Features'}

-

- {lang === 'zh' - ? '为稳定、低延迟的全球访问而生。' - : 'Built for stable, low-latency global access.'} -

+

{intro}

{items.map(({ title, description, icon: Icon }) => (