This is an automated email from the ASF dual-hosted git repository.
JiaLiangC pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ambari-website.git
The following commit(s) were added to refs/heads/main by this push:
new 137d81c AMBARI-26651: Document React UI and View extensions (#43)
137d81c is described below
commit 137d81c61cbb7b7ecf658cf722daf7fae60701cd
Author: jialiang <[email protected]>
AuthorDate: Wed Sep 9 01:51:04 2026 +0000
AMBARI-26651: Document React UI and View extensions (#43)
---
.../ambari-design/views/developing-react-views.md | 250 +++++++++++++++++
.../version-3.1.0/ambari-design/views/index.md | 1 +
.../version-3.1.0/frontend/customizing-react-ui.md | 170 ++++++++++++
.../version-3.1.0/frontend/react-ui.md | 4 +
tests/e2e/i18n.spec.ts | 2 +-
tests/i18n.test.mjs | 6 +-
.../ambari-design/views/developing-react-views.md | 306 +++++++++++++++++++++
.../version-3.1.0/ambari-design/views/index.md | 1 +
.../version-3.1.0/frontend/customizing-react-ui.md | 224 +++++++++++++++
versioned_docs/version-3.1.0/frontend/react-ui.md | 4 +
versioned_sidebars/version-3.1.0-sidebars.json | 2 +
11 files changed, 967 insertions(+), 3 deletions(-)
diff --git
a/i18n/zh-Hans/docusaurus-plugin-content-docs/version-3.1.0/ambari-design/views/developing-react-views.md
b/i18n/zh-Hans/docusaurus-plugin-content-docs/version-3.1.0/ambari-design/views/developing-react-views.md
new file mode 100644
index 0000000..a6be987
--- /dev/null
+++
b/i18n/zh-Hans/docusaurus-plugin-content-docs/version-3.1.0/ambari-design/views/developing-react-views.md
@@ -0,0 +1,250 @@
+---
+title: 开发 React View
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# 开发和部署 React View {#develop-and-deploy-react-view}
+
+Ambari View 是由 Ambari Server 管理的版本化应用归档。它可以包含浏览器应用、JAX-RS 资源、实例参数、权限和生命周期钩子。主要
React shell 会发现用户有权访问的 View 实例,并在 Server 提供的同源 iframe 上下文中打开应用。
+
+文件浏览器、调度器编辑器、诊断控制台或 AI 辅助运维页面等可独立部署的工具适合使用 View。需要修改 Ambari
公共导航或内置工作流时,则应修改[主要 React UI](../../frontend/customizing-react-ui.md)。
+
+## 参考实现 {#reference-implementations}
+
+Ambari `trunk` 包含两个 React View 实现:
+
+| View | 前端 | Server 资源 | 可参考的模式 |
+| --- | --- | --- | --- |
+| Files | `contrib/views/files/src/main/resources/ui` |
`contrib/views/files/src/main/java` | 能识别部署路径的 API 根路径、文件操作、上传下载、错误处理和反向代理测试 |
+| Capacity Scheduler |
`contrib/views/capacity-scheduler/src/main/resources/ui` |
`contrib/views/capacity-scheduler/src/main/java` | 配置编辑、权限检查、YARN
操作、保存并刷新和保存并重启流程 |
+
+在 3.1 构建中,两者都使用 React 19、TypeScript、Vite、Vitest、Node 22.23.1 和 npm
10.9.8。可以同时参考这两个模块,但不要把其中针对 HDFS 或 YARN 的依赖复制到无关 View。
+
+## 归档结构 {#archive-layout}
+
+React View 通常使用以下目录:
+
+```text
+my-view/
+├── pom.xml
+└── src/main/
+ ├── java/org/example/ambari/view/
+ │ └── MyViewService.java
+ └── resources/
+ ├── view.xml
+ ├── view.log4j.properties
+ └── ui/
+ ├── package.json
+ ├── package-lock.json
+ ├── vite.config.ts
+ ├── index.html
+ └── src/
+```
+
+Maven 构建需要在资源处理前完成前端构建,并将生成的 `ui/dist` 文件放在归档根目录。归档还要包含 `view.xml`、View 的
Server 类,以及 `WEB-INF/lib` 下的运行时库。Ambari Server 已提供的依赖必须使用 `provided` scope;重复打包
Servlet、Jetty、Jersey 或日志实现可能破坏 View classloader。
+
+## 定义 View {#define-the-view}
+
+`src/main/resources/view.xml` 定义稳定的 View 名称、版本、配置参数、REST
资源、权限和可选的自动实例。下面是包含一个受保护资源的最小定义:
+
+```xml
+<view>
+ <name>AI-ASSISTANT</name>
+ <label>AI Assistant</label>
+ <version>1.0.0</version>
+ <min-ambari-version>3.1.*</min-ambari-version>
+
+ <parameter>
+ <name>request.timeout.seconds</name>
+ <description>Maximum time for an assisted request.</description>
+ <required>true</required>
+ <default-value>30</default-value>
+ </parameter>
+
+ <resource>
+ <name>assistant</name>
+ <service-class>org.example.ambari.view.AssistantService</service-class>
+ </resource>
+
+ <permission>
+ <name>USE_ASSISTANT</name>
+ <description>Submit requests to the assistant.</description>
+ </permission>
+</view>
+```
+
+`<name>` 和 `<version>` 会成为公开 URL 和持久化 View
标识的一部分。发布不兼容的前端、资源、参数或数据改动时,应使用新版本。需要在版本间移动实例数据时,应定义明确的迁移过程。
+
+参数属于实例配置,不能用来安全保存明文凭据。敏感值应通过 Server 端受保护凭据存储读取,绝不能返回给浏览器。
+
+完整描述符见 [View
定义](./view-definition.md),实例数据、持久化、事件和生命周期服务见[框架服务](./framework-services.md)。
+
+## 实现 Server 资源 {#implement-server-resources}
+
+`<resource>` 条目将资源名映射到 View 服务类。Ambari 会把该资源发布在经过身份验证的实例 URL 下:
+
+```text
+/api/v1/views/{view}/versions/{version}/instances/{instance}/resources/{resource}
+```
+
+在 Server 类中使用 `ViewContext` 获取当前用户、实例属性、关联集群和数据服务。每个受保护操作都要先调用
`ViewContext.hasPermission`;React UI 可以隐藏控件,但资源端点仍是最终授权边界。
+
+响应应使用有大小限制且字段明确的 DTO。验证路径、标识、查询大小和外部目标。调用 HDFS、YARN、Ambari
和外部服务时设置超时。将预期失败转换为有意义的 HTTP 状态码,但不要返回堆栈、凭据或未经限制的模型输出。
+
+### AI 辅助 View {#ai-assisted-views}
+
+AI 服务调用应放在 View 资源后面:
+
+```text
+React View
+ │ same-origin request
+ ▼
+View JAX-RS resource
+ ├── authorized Ambari or service API
+ └── approved AI provider
+```
+
+浏览器把用户请求发送给 View 资源。Server 检查 View
权限、限制请求大小、读取受保护的服务凭据、调用批准的端点、过滤响应,并记录可审计结果。不要让 React 使用长期密钥直接调用 AI 服务。AI 建议创建
Ambari 请求或变更集群状态前,还应要求用户再次确认。
+
+## 构建路径安全的 React 前端 {#build-a-path-safe-react-frontend}
+
+将 Vite 静态资源基础路径设置为相对路径,使同一归档可以适配不同的 View 名称、版本、实例和反向代理前缀:
+
+```ts
+import react from "@vitejs/plugin-react";
+import { defineConfig } from "vite";
+
+export default defineConfig({
+ base: "./",
+ plugins: [react()],
+ build: { outDir: "dist", emptyOutDir: true },
+ test: { environment: "jsdom" },
+});
+```
+
+不要从站点根目录硬编码 `/api/v1`。View 可能发布在 `/gateway/default/ambari/views/...` 等路径下。应从当前
pathname 推导 Ambari 应用根路径,再构建经过编码的资源 URL:
+
+```ts
+const applicationRoot = (pathname: string) => {
+ const normalized = pathname.startsWith("/") ? pathname : `/${pathname}`;
+ const viewsIndex = normalized.lastIndexOf("/views/");
+ return viewsIndex >= 0 ? `${normalized.slice(0, viewsIndex)}/` : "/";
+};
+
+const resourceRoot = `${applicationRoot(window.location.pathname)}api/v1/` +
+ `views/${encodeURIComponent(view)}/versions/${encodeURIComponent(version)}/`
+
+ `instances/${encodeURIComponent(instance)}/resources/assistant`;
+```
+
+资源请求需要发送会话凭据和 Ambari CSRF 请求头:
+
+```ts
+const response = await fetch(`${resourceRoot}/query`, {
+ method: "POST",
+ credentials: "same-origin",
+ headers: {
+ "Content-Type": "application/json",
+ "X-Requested-By": "ai-assistant-view",
+ },
+ body: JSON.stringify(request),
+});
+```
+
+除非用户明确离开 View,否则导航应留在 View 自己的 hash 或相对路径内。需要测试 Ambari 可能提供的两种规范路径:
+
+```text
+/views/{view}/{version}/{instance}/
+/views/{view}/{instance}/
+```
+
+Files 和 Capacity Scheduler 的 API helper 会定位最后一个 `/views/`
片段。这样既能保留反向代理前缀,也不会把前面同名的路径片段误认为 View 上下文。
+
+## 构建并检查归档 {#build-and-inspect-the-archive}
+
+在任一参考模块中只迭代前端时:
+
+```shell
+cd contrib/views/files/src/main/resources/ui
+npm ci --no-audit --no-fund
+npm test
+npm run build
+```
+
+从 Ambari 仓库根目录构建完整参考归档:
+
+```shell
+mvn -B -pl :files -am package
+mvn -B -pl :capacity-scheduler -am package
+```
+
+新模块应将 artifact selector 换成自己的 Maven artifact ID。部署前检查产物:
+
+```shell
+jar tf target/my-view-1.0.0.jar | sort
+```
+
+确认归档包含 `view.xml`、`index.html`、`index.html` 引用的全部哈希资源、Server
类,并且只包含预期的运行时依赖。Java 资源测试和前端测试应与其验证的行为放在同一个改动中。
+
+## 部署 View {#deploy-the-view}
+
+默认 View 归档目录是 `/var/lib/ambari-server/resources/views`。向自定义 Server 部署前,应先检查
`ambari.properties` 中的 `views.dir`。
+
+安装经过审查的归档并重启 Ambari Server:
+
+```shell
+install -m 0644 target/my-view-1.0.0.jar \
+ /var/lib/ambari-server/resources/views/
+ambari-server restart
+```
+
+查看 `ambari-server.log`,确认 View 版本进入
`DEPLOYED`。classloader、描述符或依赖错误会使该版本不可用,创建实例前必须先解决。不要在相同版本下反复用不同内容覆盖正在使用的归档;应发布新版本,使部署、回退和数据迁移保持明确。
+
+在 Ambari 管理 UI 中创建并配置实例,然后向所需用户或组授予该实例及自定义 View 权限。等效的实例 API 见 [View
API](./view-api.md)。
+
+有权限的实例会从 Server 返回的 URL 打开,例如:
+
+```text
+/views/AI-ASSISTANT/1.0.0/PRODUCTION/
+```
+
+不要根据猜测的主机名或上下文根路径拼接浏览器 URL。尤其当 Server 位于 Knox 或其他反向代理后面时,应读取 Ambari 返回的实例 URL。
+
+## 验证清单 {#validation-checklist}
+
+分发 View 归档之前:
+
+* 运行前端单元测试、TypeScript 构建和 Vite 生产构建。
+* 为每个 JAX-RS 资源和权限分支运行定向 Java 测试。
+* 检查归档内容和依赖版本。
+* 部署全新版本、创建实例并按最小权限授权。
+* 测试允许、拒绝、未认证、会话过期和 CSRF 失败场景。
+* 测试正常、空数据、格式错误、超时、重试和后端不可用场景。
+* 验证根路径和反向代理上下文路径下的 View 直接导航。
+* 检查刷新、浏览器后退、iframe 错误、窄屏和键盘操作。
+* 确认日志、响应、浏览器存储和 bundle 中没有凭据。
+* 升级到新的 View 版本,并演练回退或数据迁移。
+
+## 相关文档 {#related-documentation}
+
+* [Views 概览](./index.md)
+* [View 定义](./view-definition.md)
+* [框架服务](./framework-services.md)
+* [View API](./view-api.md)
+* [定制 React UI](../../frontend/customizing-react-ui.md)
+* [从源码构建 Ambari](../../ambari-dev/building-from-source.md)
diff --git
a/i18n/zh-Hans/docusaurus-plugin-content-docs/version-3.1.0/ambari-design/views/index.md
b/i18n/zh-Hans/docusaurus-plugin-content-docs/version-3.1.0/ambari-design/views/index.md
index 15e75bb..c4659ea 100644
---
a/i18n/zh-Hans/docusaurus-plugin-content-docs/version-3.1.0/ambari-design/views/index.md
+++
b/i18n/zh-Hans/docusaurus-plugin-content-docs/version-3.1.0/ambari-design/views/index.md
@@ -41,6 +41,7 @@ View-only 用户会获得精简的 Views shell。独立的 Ambari Admin React
## 文档导航 {#documentation-map}
+* [React View 开发](./developing-react-views.md)介绍前端和 Server 结构、路径安全的 API
调用、权限、构建、部署和验证。
* [View API](./view-api.md)介绍通过 Ambari REST API 发现 View、查看版本、创建实例以及管理权限和特权。
* [View Definition](./view-definition.md)介绍当前 `view.xml` 契约和软件包元数据。
* [框架服务](./framework-services.md)介绍 `ViewContext`、实例数据、资源提供程序和生命周期事件。
diff --git
a/i18n/zh-Hans/docusaurus-plugin-content-docs/version-3.1.0/frontend/customizing-react-ui.md
b/i18n/zh-Hans/docusaurus-plugin-content-docs/version-3.1.0/frontend/customizing-react-ui.md
new file mode 100644
index 0000000..1cce41a
--- /dev/null
+++
b/i18n/zh-Hans/docusaurus-plugin-content-docs/version-3.1.0/frontend/customizing-react-ui.md
@@ -0,0 +1,170 @@
+---
+title: 定制 React UI
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# 定制 React UI {#customize-react-ui}
+
+Ambari 3.1 从 `ambari-web/latest` 提供主要 Web UI。本指南说明如何修改该应用、验证改动、构建 Server Web
制品,以及测试开发环境部署。它适用于应该进入 Ambari 公共 shell 或内置工作流的改动。
+
+能够独立部署的工具通常更适合实现为 Ambari View。在主要 UI 中添加产品专用页面之前,请先阅读 [React View
开发](../ambari-design/views/developing-react-views.md)。
+
+## 选择扩展边界 {#choose-extension-boundary}
+
+| 需求 | 扩展点 | 原因 |
+| --- | --- | --- |
+| 修改公共导航、身份验证、主机、服务、配置、告警或其他内置工作流 | `ambari-web/latest` | 此功能需要参与主要
shell、共享状态和 Ambari 权限控制。 |
+| 添加具有独立版本、UI 和 REST 资源的应用 | [Ambari
View](../ambari-design/views/developing-react-views.md) | View 无需重新构建主要
UI,就可以单独打包、部署、升级和分配权限。 |
+| 修改服务配置布局或控件 | [服务 Theme](../ambari-design/stack-and-services/extensions.md)
| 服务专用的配置展示由 Stack 元数据管理。 |
+| 添加编排、持久化或高权限操作 | Ambari Server API 加上以上一种 UI 扩展方式 | Server
必须是权限判断和变更操作的最终依据。 |
+
+不要因为不想创建 View,就把功能直接塞进主要 UI。核心 UI 改动会影响每套 Ambari,需要兼容所有支持的身份验证、权限、代理和集群状态行为。
+
+## 环境要求与基线 {#requirements-and-baseline}
+
+使用当前 Ambari `trunk` 源码和其中声明的工具链。3.1 基线使用 JDK 17、Maven 3.9.x、Node 22.23.1 和 npm
10.9.8。Maven 前端插件会下载锁定的 Node 和 npm 版本;直接运行前端命令时,`PATH` 中需要存在兼容版本。
+
+修改 UI 之前:
+
+1. 确认工作树基于目标 `trunk` 修订。
+2. 阅读附近的测试以及相关 Server API 或 Stack 契约。
+3. 不要编辑 `latest/dist` 或 `target/classes/latest`,它们都是生成目录。
+4. 不要把产品凭据和高权限逻辑放进浏览器代码。
+
+## 源码目录 {#source-map}
+
+| 路径 | 职责 |
+| --- | --- |
+| `ambari-web/latest/src/router/RoutesList.tsx` | 路由树,以及路由级权限、功能和操作状态保护 |
+| `ambari-web/latest/src/screens` | 工作流与页面实现 |
+| `ambari-web/latest/src/api` | Ambari REST 客户端、请求载荷和响应处理 |
+| `ambari-web/latest/src/store` | 已认证用户、集群、服务和应用共享状态 |
+| `ambari-web/latest/src/components` | 可复用控件、进度展示、路由保护、导航和 View 集成 |
+| `ambari-web/latest/src/locales` | 英文和简体中文 UI 文案 |
+| `ambari-web/latest/src/test` | 共享 Vitest 和 jsdom 测试设置 |
+| `ambari-web/latest/vite.config.ts` | Vite 基础路径、React 插件和测试配置 |
+
+优先沿用相邻功能的实现,不要创建第二套请求、状态或通知模式。例如,新的服务操作应该复用现有的请求进度模型,不能把 API 已受理误认为操作已经完成。
+
+## 开发核心 UI 改动 {#develop-a-core-ui-change}
+
+### 安装、测试与构建 {#install-test-and-build}
+
+直接运行前端命令可以获得最短的修改反馈周期:
+
+```shell
+cd ambari-web/latest
+npm ci --no-audit --no-fund
+npm test
+npm run build
+```
+
+`npm run build` 会执行 TypeScript 构建,并把新的 Vite bundle 写入
`ambari-web/latest/dist`。`npm test` 会运行完整 Vitest 测试。还应执行 `npm run
lint`,但要将仓库级结果与未修改的 `trunk` 基线比较,不要把已有 lint 问题都归因于本次改动。
+
+Vite 开发服务器适合组件开发:
+
+```shell
+npm run dev -- --host 127.0.0.1
+```
+
+它本身不会还原 Ambari Server 身份验证、WebSocket 消息、View
托管或反向代理前缀。要验证集成行为,必须使用打包后的部署,或者配置同源开发代理。
+
+### 添加路由与导航 {#add-routes-and-navigation}
+
+在 `RoutesList.tsx` 中注册内置路由,并使用现有保护组件:
+
+* `ProtectedRoute` 检查 Ambari 权限名,并提供安全的回退页面。
+* `FeatureRouteGuard` 检查 Stack 或 Server 功能标志。
+* `ServiceOperationRouteGuard` 防止互相冲突的服务工作流同时运行。
+* 特定工作流的保护组件负责持久化的所有者和恢复状态。
+
+隐藏导航入口不等于完成授权。直接访问的路由也必须受保护,Server API 还要检查相同权限。需要测试直接输入
URL、浏览器刷新、无权限角色、关闭的功能标志和冲突中的操作。
+
+### 复用 API 与状态契约 {#use-shared-api-and-state-contracts}
+
+把 REST 调用放在 `src/api` 下,并复用已配置的 `ambariApi`
客户端。该客户端会发送同源凭据,并统一处理身份验证失败。变更类请求应沿用现有端点对
`X-Requested-By`、内容类型和载荷结构的处理;不要内置用户名、密码、token 或外部服务密钥。
+
+Ambari 操作是异步的。变更操作创建请求后,需要保留 request ID,跟踪 Server
中的权威任务状态,展示失败主机或任务,并在刷新后提供同样受支持的重试或恢复入口。不要用定时器或乐观成功提示替代 Server 状态。
+
+### 保持本地化与可访问性 {#preserve-localization-and-accessibility}
+
+用户可见文案要同时加入 `src/locales/en/translation.json` 和
`src/locales/zh/translation.json`。API
载荷使用稳定资源标识,只翻译展示标签。新控件需要支持键盘操作、提供可访问名称、保留清晰焦点,并展示加载、空数据、成功和失败状态,不能只依赖颜色传递信息。
+
+## 构建 Server Web 制品 {#build-the-server-web-artifact}
+
+Maven 模块会锁定前端工具链、构建 React 应用,并把 `latest/dist` 复制到
`ambari-web/target/classes/latest`:
+
+```shell
+mvn -B -pl :ambari-web -am \
+ -DskipTests -DskipPythonTests=true package
+```
+
+受支持的交付方式是构建并安装经过审查的 Ambari Server 软件包。这样可以让 Web 文件、Java
制品、版本元数据和软件包所有权保持一致。不要把 `node_modules`、Vite 开发服务器或源码复制到受管集群节点。
+
+## 在开发环境替换静态文件 {#replace-static-files-for-development}
+
+默认 RPM 配置将 `webapp.dir` 设为 `/usr/lib/ambari-server/web`,React 应用从它的 `latest`
子目录提供。自定义安装可能在 `ambari.properties` 中设置不同的 `webapp.dir`,替换前应先检查实际配置。
+
+在一次性开发 Server 上,可以先停止 Server,再暂存并整体切换 `dist` 目录:
+
+```shell
+ambari-server stop
+stamp=$(date +%Y%m%d%H%M%S)
+install -d /usr/lib/ambari-server/web/latest.new
+cp -a /path/to/ambari-web/latest/dist/. \
+ /usr/lib/ambari-server/web/latest.new/
+mv /usr/lib/ambari-server/web/latest \
+ "/usr/lib/ambari-server/web/latest.${stamp}"
+mv /usr/lib/ambari-server/web/latest.new \
+ /usr/lib/ambari-server/web/latest
+ambari-server start
+```
+
+必须整体切换目录。Vite 文件名带有内容哈希,只复制部分文件可能使 `index.html`
指向不兼容的资源集合。验证完成前保留带时间戳的目录。需要回退时,停止 Server,将失败的 `latest` 目录移开,把带时间戳的目录恢复为
`latest`,再启动 Server。
+
+这套流程只适用于开发环境。生产改动应该通过有版本、可审查的软件包和站点正常发布流程交付。
+
+## 验证清单 {#validation-checklist}
+
+不要只验证页面能否成功打开:
+
+* 对改动的页面、API 客户端、store 和保护组件运行定向测试。
+* 运行完整 Vitest 测试和生产构建。
+* 通过部署环境实际使用的基础路径和 TLS 入口打开 `/latest/#`。
+* 测试本地登录、已配置的 SSO、会话过期和退出。
+* 通过导航和直接 URL 分别测试有权限与无权限角色。
+* 注入 API 拒绝、超时、部分任务失败、刷新和重试。
+* 验证英文、简体中文、键盘操作和窄屏布局。
+* 如果页面使用实时状态,检查 WebSocket 或轮询恢复。
+* 检查浏览器控制台、网络请求、CSP 行为和 Server 日志。
+
+## 安全规则 {#security-rules}
+
+浏览器代码应视为公开内容。不得将密码、API token、私钥或 AI 服务凭据编译进 React bundle 或 `VITE_`
变量。需要高权限的外部调用必须经过 Server 端点,并使用受保护的凭据存储、明确授权、输入输出限制和可审计的错误处理。
+
+不要把 Server 或模型输出直接作为原始 HTML 渲染。保留 Ambari 的同源凭据模式、CSRF
请求头约定、CSP、代理前缀和权限检查。React 路由保护能改善用户体验,但不能替代 Server 权限检查。
+
+## 相关文档 {#related-documentation}
+
+* [React 用户指南](./react-ui.md)
+* [React View 开发](../ambari-design/views/developing-react-views.md)
+* [从源码构建 Ambari](../ambari-dev/building-from-source.md)
+* [运行测试](../ambari-dev/running-tests.md)
+* [View 定义](../ambari-design/views/view-definition.md)
+* [Stack 扩展](../ambari-design/stack-and-services/extensions.md)
diff --git
a/i18n/zh-Hans/docusaurus-plugin-content-docs/version-3.1.0/frontend/react-ui.md
b/i18n/zh-Hans/docusaurus-plugin-content-docs/version-3.1.0/frontend/react-ui.md
index a504e80..b24012a 100644
---
a/i18n/zh-Hans/docusaurus-plugin-content-docs/version-3.1.0/frontend/react-ui.md
+++
b/i18n/zh-Hans/docusaurus-plugin-content-docs/version-3.1.0/frontend/react-ui.md
@@ -69,6 +69,8 @@ Stack 管理包括版本列表、仓库信息、升级和降级启动、预检
Views 从已认证的 React shell 列出,并在服务器提供的同源 iframe 上下文中打开。View-only 用户获得精简
shell,并可直接导航到 Views。Ambari Admin 是位于
`ambari-admin/src/main/resources/ui/ambari-admin` 的独立 React 模块;其打包的 React
`latest` 输出与主 UI 一起构建。
+完整的 View 扩展流程,包括路径安全的 React 前端、JAX-RS 资源、权限、打包和部署,参阅 [React View
开发](../ambari-design/views/developing-react-views.md)。
+
服务 Theme 提供由 Stack 定义的页面布局、配置控件、属性、条件、建议,以及只读状态和权限处理。当前实现已经具备 Theme
解析和具有代表性的使用方;自定义 Stack、复杂条件组合和保存后重新加载的一致性仍需结合真实环境验收。
## 原生 Monitoring {#native-monitoring}
@@ -83,6 +85,8 @@ React 在 `/main/monitoring` 提供原生 Prometheus 兼容监控区域,包括
Maven 的 `ambari-web` 模块使用配置的 Node/npm 工具链,从 `ambari-web/latest` 构建主要 React
应用并写入 `latest/dist`;Maven 会将该输出复制到服务器 Web UI 构件中。独立的 `ambari-admin` 模块从
`src/main/resources/ui/ambari-admin` 构建 Admin React 应用,并将输出打包到 `classes/latest`。
+源码目录、路由和 API 约定、测试命令、Server 制品构建,以及仅用于开发环境的静态文件替换流程,参阅[定制 React
UI](./customizing-react-ui.md)。
+
升级和管理流程参阅[升级指南](../upgrade-guide.md)。部署构件应使用目标 Ambari
安装相同的基础路径、代理上下文和身份验证模式进行检查。
## 验收清单 {#acceptance-checklist}
diff --git a/tests/e2e/i18n.spec.ts b/tests/e2e/i18n.spec.ts
index c52513b..247a75a 100644
--- a/tests/e2e/i18n.spec.ts
+++ b/tests/e2e/i18n.spec.ts
@@ -168,7 +168,7 @@ test('3.1 preview routes are bilingual and preserve the
stable default', async (
const data = JSON.parse(readFileSync('.docusaurus/globalData.json', 'utf8'));
const versions = data['docusaurus-plugin-content-docs'].default.versions;
const preview = versions.find(item => item.name === '3.1.0');
- expect(preview.docs).toHaveLength(71);
+ expect(preview.docs).toHaveLength(73);
expect(preview.isLast).toBe(false);
expect(versions.find(item => item.name === '3.0.0').isLast).toBe(true);
expect(versions.some(item => item.name === 'current')).toBe(false);
diff --git a/tests/i18n.test.mjs b/tests/i18n.test.mjs
index 2fb12e4..3e8af58 100644
--- a/tests/i18n.test.mjs
+++ b/tests/i18n.test.mjs
@@ -118,15 +118,17 @@ test('3.1.0 retains current general documentation without
obsolete tutorial rout
'monitoring/service-integration', 'monitoring/migration',
'platform/java-dependencies', 'platform/python-runtime',
'platform/rpm-packaging', 'frontend/react-ui',
+ 'frontend/customizing-react-ui',
'quick-start/installation-guide', 'quick-start/download',
'ambari-design/blueprints/index', 'ambari-design/kerberos/index',
- 'ambari-design/views/index', 'ambari-design/stack-and-services/index',
+ 'ambari-design/views/index', 'ambari-design/views/developing-react-views',
+ 'ambari-design/stack-and-services/index',
'ambari-design/enhanced-configs/index', 'ambari-design/alerts',
'ambari-dev/building-from-source', 'ambari-dev/how-to-contribute',
'ambari-dev/running-tests', 'ambari-plugin-contribution/index',
];
for (const id of required) assert.ok(ids.includes(id), `Missing supported
documentation: ${id}`);
- assert.equal(ids.length, 71);
+ assert.equal(ids.length, 73);
assert.equal(new Set(ids).size, ids.length);
assert.ok(!ids.some(id => id.startsWith('ambari-design/metrics/') ||
id.startsWith('ambari-plugin-contribution/scom/')));
assert.ok(!ids.includes('ambari-plugin-contribution/step-by-step'));
diff --git
a/versioned_docs/version-3.1.0/ambari-design/views/developing-react-views.md
b/versioned_docs/version-3.1.0/ambari-design/views/developing-react-views.md
new file mode 100644
index 0000000..8c26e3d
--- /dev/null
+++ b/versioned_docs/version-3.1.0/ambari-design/views/developing-react-views.md
@@ -0,0 +1,306 @@
+---
+title: Developing React Views
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Develop And Deploy A React View {#develop-and-deploy-react-view}
+
+An Ambari View is a versioned application archive managed by Ambari Server. It
+can contain a browser application, JAX-RS resources, instance parameters,
+permissions, and lifecycle hooks. The primary React shell discovers authorized
+View instances and opens each application in a Server-provided same-origin
+iframe context.
+
+Use a View for a separately deployable tool such as a file browser, scheduler
+editor, diagnostics console, or AI-assisted operations page. Use
+[the primary React UI](../../frontend/customizing-react-ui.md) when a feature
+must change shared Ambari navigation or a built-in workflow.
+
+## Reference Implementations {#reference-implementations}
+
+Ambari `trunk` contains two React View implementations:
+
+| View | Frontend | Server resources | Useful patterns |
+| --- | --- | --- | --- |
+| Files | `contrib/views/files/src/main/resources/ui` |
`contrib/views/files/src/main/java` | Path-aware API root, file operations,
upload/download, errors, and reverse-proxy tests |
+| Capacity Scheduler |
`contrib/views/capacity-scheduler/src/main/resources/ui` |
`contrib/views/capacity-scheduler/src/main/java` | Configuration editing,
privilege checks, YARN operations, save/refresh, and save/restart flows |
+
+Both use React 19, TypeScript, Vite, Vitest, Node 22.23.1, and npm 10.9.8 in
+the 3.1 build. Study both modules, but do not copy their HDFS or YARN
+dependencies into an unrelated View.
+
+## Archive Layout {#archive-layout}
+
+A React View normally follows this layout:
+
+```text
+my-view/
+├── pom.xml
+└── src/main/
+ ├── java/org/example/ambari/view/
+ │ └── MyViewService.java
+ └── resources/
+ ├── view.xml
+ ├── view.log4j.properties
+ └── ui/
+ ├── package.json
+ ├── package-lock.json
+ ├── vite.config.ts
+ ├── index.html
+ └── src/
+```
+
+The Maven build must run the frontend build before resource processing and
+package the generated `ui/dist` files at the archive root. It also packages
+`view.xml`, the View's Server classes, and runtime libraries under
+`WEB-INF/lib`. Dependencies supplied by Ambari Server must use `provided`
+scope; bundling a second Servlet, Jetty, Jersey, or logging implementation can
+break the View classloader.
+
+## Define The View {#define-the-view}
+
+`src/main/resources/view.xml` defines the stable View name, version,
+configuration parameters, REST resources, permissions, and optional automatic
+instances. A minimal definition with one protected resource looks like this:
+
+```xml
+<view>
+ <name>AI-ASSISTANT</name>
+ <label>AI Assistant</label>
+ <version>1.0.0</version>
+ <min-ambari-version>3.1.*</min-ambari-version>
+
+ <parameter>
+ <name>request.timeout.seconds</name>
+ <description>Maximum time for an assisted request.</description>
+ <required>true</required>
+ <default-value>30</default-value>
+ </parameter>
+
+ <resource>
+ <name>assistant</name>
+ <service-class>org.example.ambari.view.AssistantService</service-class>
+ </resource>
+
+ <permission>
+ <name>USE_ASSISTANT</name>
+ <description>Submit requests to the assistant.</description>
+ </permission>
+</view>
+```
+
+The `<name>` and `<version>` values become part of the public URL and persisted
+View identity. Use a new version when releasing incompatible frontend,
+resource, parameter, or data changes. Define an explicit migration when
+instance data must move between versions.
+
+Parameters are instance configuration, not a safe place for plaintext
+credentials. Resolve sensitive values through Server-side protected credential
+storage and never return them to the browser.
+
+See [View Definition](./view-definition.md) for the complete descriptor and
+[Framework Services](./framework-services.md) for instance data, persistence,
+events, and lifecycle services.
+
+## Implement Server Resources {#implement-server-resources}
+
+The `<resource>` entry maps a name to a View service class. Ambari publishes
+that resource below the authenticated instance URL:
+
+```text
+/api/v1/views/{view}/versions/{version}/instances/{instance}/resources/{resource}
+```
+
+Use `ViewContext` in the Server class to obtain the current user, instance
+properties, cluster association, and data services. Call
+`ViewContext.hasPermission` before each protected operation; the React UI may
+hide a control, but the resource remains the authorization boundary.
+
+Return bounded, explicit DTOs. Validate paths, identifiers, query sizes, and
+outbound destinations. Set timeouts on HDFS, YARN, Ambari, and external-service
+calls. Convert expected failures into useful HTTP status codes without
+returning stack traces, credentials, or unrestricted model output.
+
+### AI-Assisted Views {#ai-assisted-views}
+
+Keep AI-provider access behind the View resource:
+
+```text
+React View
+ │ same-origin request
+ ▼
+View JAX-RS resource
+ ├── authorized Ambari or service API
+ └── approved AI provider
+```
+
+The browser sends the user's request to the View resource. The Server checks
+the View permission, limits the request, loads the protected provider
+credential, calls the approved endpoint, filters the response, and records an
+auditable result. Never call a provider with a long-lived key from React.
+Require an additional confirmation before an AI suggestion can create an
+Ambari request or mutate cluster state.
+
+## Build A Path-Safe React Frontend {#build-a-path-safe-react-frontend}
+
+Set Vite's asset base to a relative path so the same archive works with View
+names, versions, instances, and reverse-proxy prefixes:
+
+```ts
+import react from "@vitejs/plugin-react";
+import { defineConfig } from "vite";
+
+export default defineConfig({
+ base: "./",
+ plugins: [react()],
+ build: { outDir: "dist", emptyOutDir: true },
+ test: { environment: "jsdom" },
+});
+```
+
+Do not hard-code `/api/v1` from the origin root. A View may be served at a path
+such as `/gateway/default/ambari/views/...`. Derive the Ambari application root
+from the current pathname and build the encoded resource URL:
+
+```ts
+const applicationRoot = (pathname: string) => {
+ const normalized = pathname.startsWith("/") ? pathname : `/${pathname}`;
+ const viewsIndex = normalized.lastIndexOf("/views/");
+ return viewsIndex >= 0 ? `${normalized.slice(0, viewsIndex)}/` : "/";
+};
+
+const resourceRoot = `${applicationRoot(window.location.pathname)}api/v1/` +
+ `views/${encodeURIComponent(view)}/versions/${encodeURIComponent(version)}/`
+
+ `instances/${encodeURIComponent(instance)}/resources/assistant`;
+```
+
+Send session credentials and Ambari's CSRF header on resource requests:
+
+```ts
+const response = await fetch(`${resourceRoot}/query`, {
+ method: "POST",
+ credentials: "same-origin",
+ headers: {
+ "Content-Type": "application/json",
+ "X-Requested-By": "ai-assistant-view",
+ },
+ body: JSON.stringify(request),
+});
+```
+
+Keep navigation inside the View's own hash or relative paths unless the user
+explicitly leaves the View. Test both canonical paths that Ambari may provide:
+
+```text
+/views/{view}/{version}/{instance}/
+/views/{view}/{instance}/
+```
+
+The Files and Capacity Scheduler API helpers locate the last `/views/` segment,
+which preserves a reverse-proxy prefix and avoids confusing an earlier path
+segment with the View context.
+
+## Build And Inspect The Archive {#build-and-inspect-the-archive}
+
+For frontend-only iteration in either reference module:
+
+```shell
+cd contrib/views/files/src/main/resources/ui
+npm ci --no-audit --no-fund
+npm test
+npm run build
+```
+
+Build the complete reference archives from the Ambari repository root:
+
+```shell
+mvn -B -pl :files -am package
+mvn -B -pl :capacity-scheduler -am package
+```
+
+For a new module, replace the artifact selector with its Maven artifact ID.
+Inspect the result before deployment:
+
+```shell
+jar tf target/my-view-1.0.0.jar | sort
+```
+
+Confirm that the archive contains `view.xml`, `index.html`, every hashed asset
+referenced by `index.html`, Server classes, and only the intended runtime
+libraries. Run Java resource tests and frontend tests in the same change as the
+behavior they verify.
+
+## Deploy The View {#deploy-the-view}
+
+The default View archive directory is
+`/var/lib/ambari-server/resources/views`. Check the `views.dir` value in
+`ambari.properties` before deploying to a customized Server.
+
+Install the reviewed archive and restart Ambari Server:
+
+```shell
+install -m 0644 target/my-view-1.0.0.jar \
+ /var/lib/ambari-server/resources/views/
+ambari-server restart
+```
+
+Watch `ambari-server.log` for the View version to reach `DEPLOYED`. A
classload,
+descriptor, or dependency error leaves the version unavailable and must be
+fixed before creating an instance. Do not repeatedly overwrite an active
+archive with different content under the same version; publish a new version
+so deployment, rollback, and data migration remain explicit.
+
+Create and configure an instance from the Ambari Administration UI, then grant
+the required users or groups access to that instance and any custom View
+permissions. The equivalent instance API is documented in
+[View API](./view-api.md).
+
+An authorized instance is opened at its Server-provided URL, for example:
+
+```text
+/views/AI-ASSISTANT/1.0.0/PRODUCTION/
+```
+
+Do not construct that browser URL from a guessed host or context root. Read the
+instance URL returned by Ambari, particularly when Knox or another reverse
+proxy fronts the Server.
+
+## Validation Checklist {#validation-checklist}
+
+Before distributing a View archive:
+
+* Run frontend unit tests, the TypeScript build, and the production Vite build.
+* Run focused Java tests for every JAX-RS resource and permission branch.
+* Inspect archive contents and dependency versions.
+* Deploy a clean version, create an instance, and grant least-privilege access.
+* Test allowed, denied, unauthenticated, expired-session, and CSRF failure
cases.
+* Test normal, empty, malformed, timeout, retry, and backend-unavailable paths.
+* Verify direct View navigation under root and reverse-proxy context paths.
+* Check refresh, browser Back, iframe errors, narrow viewports, and keyboard
use.
+* Verify that logs, responses, browser storage, and bundles contain no secrets.
+* Upgrade to a new View version and exercise rollback or data migration.
+
+## Related Documentation {#related-documentation}
+
+* [Views Overview](./index.md)
+* [View Definition](./view-definition.md)
+* [Framework Services](./framework-services.md)
+* [View API](./view-api.md)
+* [Customizing The React UI](../../frontend/customizing-react-ui.md)
+* [Building Ambari From Source](../../ambari-dev/building-from-source.md)
diff --git a/versioned_docs/version-3.1.0/ambari-design/views/index.md
b/versioned_docs/version-3.1.0/ambari-design/views/index.md
index 80c3ea1..1278e8e 100644
--- a/versioned_docs/version-3.1.0/ambari-design/views/index.md
+++ b/versioned_docs/version-3.1.0/ambari-design/views/index.md
@@ -41,6 +41,7 @@ View-only users receive the reduced Views shell. The separate
Ambari Admin React
## Documentation Map {#documentation-map}
+* [Developing React Views](./developing-react-views.md) covers frontend and
Server structure, path-safe API calls, permissions, build, deployment, and
validation.
* [View API](./view-api.md) covers discovery, versions, instances,
permissions, and privileges through the Ambari REST API.
* [View Definition](./view-definition.md) covers the current `view.xml`
contract and package metadata.
* [Framework Services](./framework-services.md) covers `ViewContext`, instance
data, resource providers, and lifecycle events.
diff --git a/versioned_docs/version-3.1.0/frontend/customizing-react-ui.md
b/versioned_docs/version-3.1.0/frontend/customizing-react-ui.md
new file mode 100644
index 0000000..c54d8ae
--- /dev/null
+++ b/versioned_docs/version-3.1.0/frontend/customizing-react-ui.md
@@ -0,0 +1,224 @@
+---
+title: Customizing The React UI
+---
+
+<!--
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements. See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+# Customize The React UI {#customize-react-ui}
+
+Ambari 3.1 serves the primary Web UI from `ambari-web/latest`. This guide
+explains how to change that application, validate the change, build the Server
+Web artifact, and test a development deployment. It applies to changes that
+belong in Ambari's shared shell or built-in workflows.
+
+An independently deployed tool normally belongs in an Ambari View instead.
+Read [Developing React Views](../ambari-design/views/developing-react-views.md)
+before adding product-specific pages to the primary UI.
+
+## Choose The Extension Boundary {#choose-extension-boundary}
+
+| Requirement | Extension point | Reason |
+| --- | --- | --- |
+| Change shared navigation, authentication, Hosts, Services, Configs, Alerts,
or another built-in workflow | `ambari-web/latest` | The feature participates
in the primary shell, shared state, and Ambari permissions. |
+| Add a separately versioned application with its own UI and REST resources |
[Ambari View](../ambari-design/views/developing-react-views.md) | A View can be
packaged, deployed, upgraded, and granted privileges without rebuilding the
primary UI. |
+| Change a service configuration layout or widget | [Service
Theme](../ambari-design/stack-and-services/extensions.md) | Stack metadata owns
service-specific configuration presentation. |
+| Add orchestration, persistence, or a privileged operation | Ambari Server
API plus one of the UI boundaries above | Authorization and mutation logic must
remain authoritative on the Server. |
+
+Do not place a feature in the primary UI only to avoid creating a View. Core UI
+changes affect every Ambari installation and must preserve all supported
+authentication, authorization, proxy, and cluster-state behavior.
+
+## Requirements And Baseline {#requirements-and-baseline}
+
+Use a current Ambari `trunk` checkout and the toolchain declared by that
+checkout. The 3.1 baseline uses JDK 17, Maven 3.9.x, Node 22.23.1, and npm
+10.9.8. The Maven frontend plugin downloads the pinned Node and npm versions;
+direct frontend commands require compatible tools on `PATH`.
+
+Before changing the UI:
+
+1. Confirm that the worktree is based on the intended `trunk` revision.
+2. Read the nearest tests and the relevant Server API or Stack contract.
+3. Do not edit `latest/dist` or `target/classes/latest`; both are generated.
+4. Keep product-specific credentials and privileged logic out of browser code.
+
+## Source Map {#source-map}
+
+| Path | Responsibility |
+| --- | --- |
+| `ambari-web/latest/src/router/RoutesList.tsx` | Route tree and route-level
permission, feature, and operation guards |
+| `ambari-web/latest/src/screens` | Workflow and page implementations |
+| `ambari-web/latest/src/api` | Ambari REST clients, request payloads, and
response handling |
+| `ambari-web/latest/src/store` | Authenticated user, cluster, service, and
shared application state |
+| `ambari-web/latest/src/components` | Reusable controls, progress, guards,
navigation, and View integration |
+| `ambari-web/latest/src/locales` | English and Simplified Chinese UI messages
|
+| `ambari-web/latest/src/test` | Shared Vitest and jsdom test setup |
+| `ambari-web/latest/vite.config.ts` | Vite base path, React plugin, and test
configuration |
+
+Follow the nearest existing feature rather than creating a second request,
+state, or notification pattern. For example, a new service operation should
+reuse the existing request-progress model instead of treating an accepted API
+response as completed work.
+
+## Develop A Core UI Change {#develop-a-core-ui-change}
+
+### Install, Test, And Build {#install-test-and-build}
+
+Run the frontend directly for the shortest edit cycle:
+
+```shell
+cd ambari-web/latest
+npm ci --no-audit --no-fund
+npm test
+npm run build
+```
+
+`npm run build` runs the TypeScript build and writes a fresh Vite bundle to
+`ambari-web/latest/dist`. `npm test` runs the complete Vitest suite. Run
+`npm run lint` as an additional check, but compare any repository-wide findings
+with the untouched `trunk` baseline instead of attributing every existing lint
+finding to the change.
+
+The Vite development server is useful for component work:
+
+```shell
+npm run dev -- --host 127.0.0.1
+```
+
+It does not reproduce Ambari Server authentication, WebSocket delivery, View
+hosting, or a reverse-proxy prefix by itself. Use a packaged deployment or a
+same-origin development proxy before claiming integration behavior.
+
+### Add Routes And Navigation {#add-routes-and-navigation}
+
+Register built-in routes in `RoutesList.tsx` and use the established guards:
+
+* `ProtectedRoute` controls Ambari authorization names and a safe fallback.
+* `FeatureRouteGuard` controls Stack or Server feature flags.
+* `ServiceOperationRouteGuard` prevents conflicting service workflows.
+* Workflow-specific guards protect persisted ownership and recovery state.
+
+Hiding a navigation item is not authorization. Protect the direct route and
+enforce the same privilege in the Server API. Test direct URL entry, browser
+refresh, unauthorized roles, disabled feature flags, and conflicting running
+operations.
+
+### Use Shared API And State Contracts {#use-shared-api-and-state-contracts}
+
+Add REST calls under `src/api` and reuse the configured `ambariApi` client. It
+sends same-origin credentials and centralizes authentication failure handling.
+Follow existing mutation endpoints for `X-Requested-By`, content type, and
+payload shape; do not embed usernames, passwords, tokens, or provider keys.
+
+Ambari operations are asynchronous. When a mutation creates a request, retain
+its request ID, follow authoritative Server task states, surface the failed
+host or task, and provide the same supported retry or recovery action after a
+refresh. Do not replace Server state with a timer or an optimistic success
+message.
+
+### Preserve Localization And Accessibility
{#preserve-localization-and-accessibility}
+
+Add user-facing messages to both
+`src/locales/en/translation.json` and
+`src/locales/zh/translation.json`. Keep stable resource identifiers in API
+payloads and translate display labels only. New controls must remain usable by
+keyboard, expose an accessible name, retain visible focus, and report loading,
+empty, success, and failure states without relying only on color.
+
+## Build The Server Web Artifact {#build-the-server-web-artifact}
+
+The Maven module pins the frontend toolchain, builds the React application, and
+copies `latest/dist` into `ambari-web/target/classes/latest`:
+
+```shell
+mvn -B -pl :ambari-web -am \
+ -DskipTests -DskipPythonTests=true package
+```
+
+The supported delivery path is to build and install reviewed Ambari Server
+packages. That keeps the Web files, Java artifacts, version metadata, and
+package ownership in sync. Do not copy `node_modules`, a Vite development
+server, or source files to a managed cluster node.
+
+## Replace Static Files For Development {#replace-static-files-for-development}
+
+The default RPM configuration sets `webapp.dir` to
+`/usr/lib/ambari-server/web`, so the React application is served from the
+`latest` child directory. A custom installation may set a different
+`webapp.dir` in `ambari.properties`; inspect that value first.
+
+For a disposable development Server, the complete `dist` directory can be
+staged and swapped while the Server is stopped:
+
+```shell
+ambari-server stop
+stamp=$(date +%Y%m%d%H%M%S)
+install -d /usr/lib/ambari-server/web/latest.new
+cp -a /path/to/ambari-web/latest/dist/. \
+ /usr/lib/ambari-server/web/latest.new/
+mv /usr/lib/ambari-server/web/latest \
+ "/usr/lib/ambari-server/web/latest.${stamp}"
+mv /usr/lib/ambari-server/web/latest.new \
+ /usr/lib/ambari-server/web/latest
+ambari-server start
+```
+
+Swap the whole directory. Vite filenames are content-hashed, so copying only
+selected files can leave `index.html` pointing at an incompatible asset set.
+Keep the timestamped directory until validation finishes. For rollback, stop
+the Server, move the failed `latest` directory aside, restore the timestamped
+directory as `latest`, and start the Server again.
+
+This procedure is for development only. Production changes should be delivered
+through versioned, reviewable packages and the site's normal rollout process.
+
+## Validation Checklist {#validation-checklist}
+
+Validate more than the successful page render:
+
+* Run focused tests for the changed screen, API client, store, and guards.
+* Run the complete Vitest suite and production build.
+* Open `/latest/#` through the deployment's real base path and TLS endpoint.
+* Exercise local login and configured SSO, session expiry, and logout.
+* Test an allowed role and a denied role by direct URL as well as navigation.
+* Inject API rejection, timeout, partial task failure, refresh, and retry.
+* Verify English and Simplified Chinese, keyboard use, and narrow viewports.
+* Check WebSocket or polling recovery if the page consumes live state.
+* Inspect the browser console, network requests, CSP behavior, and Server logs.
+
+## Security Rules {#security-rules}
+
+Treat browser code as public. Never compile a password, API token, private key,
+or AI-provider credential into the React bundle or a `VITE_` variable. A
+privileged external call needs a Server-side endpoint, protected credential
+storage, explicit authorization, input and output limits, and auditable error
+handling.
+
+Avoid rendering Server or model output as raw HTML. Preserve Ambari's
+same-origin credential model, CSRF header conventions, CSP, proxy prefix, and
+authorization checks. A React guard improves the user experience but never
+replaces a Server permission check.
+
+## Related Documentation {#related-documentation}
+
+* [React User Guide](./react-ui.md)
+* [Developing React Views](../ambari-design/views/developing-react-views.md)
+* [Building Ambari From Source](../ambari-dev/building-from-source.md)
+* [Running Tests](../ambari-dev/running-tests.md)
+* [View Definition](../ambari-design/views/view-definition.md)
+* [Stack Extensions](../ambari-design/stack-and-services/extensions.md)
diff --git a/versioned_docs/version-3.1.0/frontend/react-ui.md
b/versioned_docs/version-3.1.0/frontend/react-ui.md
index d991703..cf4f701 100644
--- a/versioned_docs/version-3.1.0/frontend/react-ui.md
+++ b/versioned_docs/version-3.1.0/frontend/react-ui.md
@@ -69,6 +69,8 @@ Stack administration includes version lists, repository
information, upgrade and
Views are listed from the authenticated React shell and opened in their
server-provided same-origin iframe context. View-only users receive a reduced
shell and can navigate directly to Views. Ambari Admin is a separate React
module under `ambari-admin/src/main/resources/ui/ambari-admin`; its packaged
React `latest` output is built alongside the main UI.
+For a complete View extension workflow, including a path-safe React frontend,
JAX-RS resources, permissions, packaging, and deployment, see [Developing React
Views](../ambari-design/views/developing-react-views.md).
+
Service Themes provide stack-defined layouts, configuration widgets,
attributes, conditions, recommendations, and read-only/permission handling.
Theme parsing and representative consumers exist, while exhaustive custom-stack
and round-trip combinations remain acceptance work.
## Native Monitoring {#native-monitoring}
@@ -83,6 +85,8 @@ The former standalone dashboard Heatmaps route redirects to
`/main/dashboard/met
The Maven `ambari-web` module builds the primary React application from
`ambari-web/latest` with the configured Node/npm toolchain and writes
`latest/dist`; the Maven package copies that output into the server Web UI
artifact. The separate `ambari-admin` module builds its Admin React application
from `src/main/resources/ui/ambari-admin` and packages its output under
`classes/latest`.
+See [Customizing The React UI](./customizing-react-ui.md) for the source map,
route and API conventions, test commands, Server artifact build, and a
development-only static file replacement procedure.
+
For upgrade and administration procedures, see the [Upgrade
Guide](../upgrade-guide.md). A deployed build should be checked with the same
base path, proxy context, and authentication mode used by the target Ambari
installation.
## Acceptance Checklist {#acceptance-checklist}
diff --git a/versioned_sidebars/version-3.1.0-sidebars.json
b/versioned_sidebars/version-3.1.0-sidebars.json
index cf505ca..ddf2764 100644
--- a/versioned_sidebars/version-3.1.0-sidebars.json
+++ b/versioned_sidebars/version-3.1.0-sidebars.json
@@ -111,6 +111,7 @@
"id": "ambari-design/views/index"
},
"items": [
+ "ambari-design/views/developing-react-views",
"ambari-design/views/view-api",
"ambari-design/views/view-definition",
"ambari-design/views/framework-services"
@@ -129,6 +130,7 @@
]
},
"frontend/react-ui",
+ "frontend/customizing-react-ui",
{
"type": "category",
"label": "Ambari Development",
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]