@qfei-design/make-app-observability
v0.1.11
Published
Shared Make App error presentation and Trace ID display contracts.
Keywords
Readme
@qfei-design/make-app-observability
Make App 统一错误展示与 Trace ID 呈现组件。它将错误卡片的布局、无障碍语义、复制反馈和 Trace ID 展示规则收敛到同一 npm 包,避免业务页面各自拼装 Toast 或 Alert。
包负责什么
- 提供无 React 依赖的错误呈现模型:
normalizeMakeAppErrorNotice。 - 为所有真实请求失败展示格式正确的 Trace ID,包括 HTTP 非 2xx、网络异常和 HTTP 2xx 的业务码错误。
- 提供与 Make App 设计一致的
MakeAppErrorNotice:错误图标、关闭按钮、Trace ID 区、复制和“已复制”状态。 - 提供响应式、作用域限定的样式,不覆盖宿主全局
button、body或弹层样式。 - 在当前源码版本中统一管理全局 Toast 的生命周期:默认三秒关闭,支持
duration秒数与0常驻;页面内提示保持常驻。
宿主负责什么
- 在统一请求适配器中生成/保存 Trace ID,并把 HTTP 状态和错误类别转换为安全的用户文案。
- 页面不得直接使用
message.error、Alert或裸fetch来呈现 Make 业务请求错误;应统一交给应用的错误出口渲染本组件。 - 在应用根节点或全局错误 Provider 中导入样式一次,并维护错误队列、业务重试和错误日志;包负责关闭计时,通过
onClose通知宿主清理队列。 - 继续确保 Service 返回
X-Log-ID、日志带 Trace ID,且不向浏览器暴露 token 或原始内部错误。
包不发起请求、不保存 Trace ID、不记录错误日志,也不自动探测宿主 UI 框架;这些运行时边界仍由 Make App 负责。
安装
pnpm add @qfei-design/make-app-observability在 Make App UI 入口导入一次样式:
import "@qfei-design/make-app-observability/styles.css";使用
import {
MakeAppErrorNotice,
MakeAppErrorNoticeViewport,
type MakeAppErrorKind,
} from "@qfei-design/make-app-observability/react";
type Props = {
kind: MakeAppErrorKind;
status?: number;
traceId?: string;
visible: boolean;
onClose: () => void;
};
export function GlobalMakeAppError(props: Props) {
if (!props.visible) return null;
return (
<MakeAppErrorNoticeViewport>
<MakeAppErrorNotice
kind={props.kind}
status={props.status}
title="process/start 网络异常,请刷新后重试或更换网络后重试"
traceId={props.traceId}
onClose={props.onClose}
/>
</MakeAppErrorNoticeViewport>
);
}MakeAppErrorNoticeViewport 在桌面和手机视口均将整个错误队列 portal 到
document.body,统一处理居中偏上、安全区、队列间距和超长内容滚动,避免单张卡片受宿主
transform containing block 影响或多张卡片相互覆盖。两端均水平居中;桌面队列默认从顶部 24px 开始向下排列,手机保持垂直居中偏上。
桌面采用顶部 Toast 定位,距顶部至少 24px 并避让安全区;手机队列中心相对可用视口中心向上偏移 clamp(24px, 5vh, 48px)。四边保留至少 12px 和安全区;长队列从安全区顶部开始并允许滚动。
宿主可通过容器的 --make-app-error-center-offset 调整手机向上偏移量(0px 为手机垂直居中),不需要额外的全屏定位 wrapper。
桌面卡片最大宽度 440px;桌面使用白底、红色左边线和紧凑标题/Trace ID 两行布局,右侧为关闭及复制图标。
手机(640px 及以下)沿用桌面的白底、灰色细边框、红色左边线、8px 圆角和普通等宽 Trace ID,仅增加底部双按钮:左侧「关闭」、右侧「复制」。手机卡片最大宽度 380px,两侧保留至少 12px 和安全区;按钮高度 32px,复制成功显示「已复制」与勾选。标题 14px,卡片留白略增,窄屏 Trace ID 自然换行。
viewport 内的卡片可带宿主 DOM wrapper,居中和卡片交互保持有效;首次服务端渲染和 hydration 保持一致,挂载后 portal 到 body。
宿主负责错误队列状态,并且一个全局错误出口只应渲染一个 viewport 容器;页面内嵌错误无需使用该容器。
viewport 默认使用 z-index: 2000;如果宿主的抽屉、预览或其他 overlay 层级更高,可通过
<MakeAppErrorNoticeViewport zIndex={2400}> 显式对齐宿主层级。portal 会脱离原宿主元素的 stacking context。
kind 必须明确传入:
http:存在合法 Trace ID 时显示。network:存在合法 Trace ID 时显示,即使没有 HTTP 状态。business:HTTP 2xx 的业务码异常同样显示合法 Trace ID,便于定位服务端校验失败。
包只消费宿主已经归一化的错误,不读取业务响应体,也不定义哪些业务 code 代表成功。
宿主请求层必须先判断 HTTP 状态,再在 HTTP 2xx 时继续判断业务 code:业务成功才返回数据,
非成功业务码应归类为 kind: "business",并优先提取公共非空字符串 msg,按接口兼容 message,连同
本次请求的 Trace ID 传入组件。不得因为 HTTP 状态为 200 就直接认定业务成功。HTTP 4xx/5xx 也保留有效公共原因;
不能按错误码或固定文案白名单覆盖具体原因和联系人,缺失公共原因时才兜底。禁止的是内部堆栈、凭据、原始 Error 和完整响应对象,
不是已确认的用户可见 msg。详细边界与宿主验收见 公共业务原因。
稳定入口和完整契约见 PUBLIC_API.md。
Toast 自动关闭(当前源码改动,尚未发布)
MakeAppErrorNoticeViewport 默认 duration={3},单位为秒。内部的全局错误卡片和权限
Toast 会在三秒后隐藏,并调用各自的 onClose 一次,供宿主清理对应队列项。
单条卡片的 duration 优先于 viewport;duration={0} 关闭自动计时,支持小数秒。
负数、NaN、Infinity 回退到有效的默认值。
<MakeAppErrorNoticeViewport duration={3}>
<MakeAppErrorNotice kind="network" title="网络异常" onClose={removeError} />
<MakeAppPermissionNotice variant="toast" duration={5} onClose={removePermissionToast} />
</MakeAppErrorNoticeViewport>无 viewport 的错误卡片默认常驻,可显式指定 duration;权限 toast 即使独立渲染也默认三秒。
权限 inline/page 始终常驻并忽略 duration。手动关闭会取消计时器;卸载不会触发关闭回调。
包自身控制隐藏,即使未提供 onClose 也会按时关闭;宿主应提供回调清理队列,不再另建关闭计时器。
回调只用于清理提示,不能自动保存、删除或重试请求。
每次重新触发提示,都从该次触发重新计算完整显示时长。推荐给每个事件传 noticeKey(字符串或数字);
即使文案、Trace ID、关闭回调都相同,只要 noticeKey 改变就会重新显示并重新计时。React key 也可用于独立通知。
<MakeAppPermissionNotice noticeKey={eventId} variant="toast" onClose={removePermissionToast} />兼容未传 noticeKey 的宿主:包把新的 onClose 函数引用视为重新触发信号,因此现有每次通知
更换关闭回调的接入方式无需改业务代码。若宿主每次普通重渲染也创建新的回调,计时同样会重置;
需要避免这种延长时,应使用显式 noticeKey。显式标识不变时,管理员加载或回调更新均不会重置计时。
如果相同文案、React key、noticeKey 与关闭回调都没有变化,包无法区分新事件与普通重渲染,宿主必须改变事件标识。
回调及计时信号只在 React 提交后更新,暂停或放弃的渲染不会影响当前提示。
需要长时间阅读或复制 Trace ID 时,宿主可以配置更长时长或 duration={0}。
以上默认行为仅存在于当前本地源码产物,接入前应核对实际安装包,不能根据相同的版本号推断。
权限拒绝提示(本分支新增,尚未发布)
新增 MakeAppPermissionNotice,在同一包内统一 Toast、表单/内容区、页面居中三种权限提示。
已发布的 0.1.8 不含此 API;接入前必须确认实际安装产物导出,版本由后续发布流程确定。
原 MakeAppErrorNotice、Trace ID 展示/复制与 viewport 默认行为保持不变。
import { MakeAppPermissionNotice, MakeAppErrorNoticeViewport } from "@qfei-design/make-app-observability/react";
import "@qfei-design/make-app-observability/styles.css";
// 内容区或表单内:放在原容器中,保留导航、标题和允许保留的输入。
<MakeAppPermissionNotice
variant="inline"
scope="resource"
administrators={administrators}
administratorStatus={administratorStatus}
retryStatus={retryStatus}
onRetry={refreshAccess}
/>
// 整个 App 无授权入口时,由宿主选择原入口的挂载位置与高度。
<MakeAppPermissionNotice variant="page" scope="app" administrators={administrators} onRetry={refreshAccess} />
// 全局 Toast 放到宿主已有的同一个错误出口,避免每个 Toast 创建 viewport。
<MakeAppErrorNoticeViewport>
<MakeAppPermissionNotice variant="toast" operationName="导出" administrators={administrators} />
</MakeAppErrorNoticeViewport>administrators 只接收当前 App 的直接授权人员 { userId, name, avatarUrl? },不传部门、Agent
或展开部门成员。Toast 显示姓名文字,inline/page 显示头像+姓名标签。空列表保留通用授权提示;
加载/查询失败不会展示旧联系人。姓名按文本渲染,头像允许 HTTPS 或安全站内绝对路径,加载失败用姓名首字。
宿主必须先确认是权限拒绝:401、未知403、租户不匹配和服务故障沿原错误出口处理,不能仅凭HTTP状态
使用此组件。包不请求管理员、不推断授权、不自动刷新或重试;包统一管理 Toast 关闭计时,宿主拥有队列状态。
onRetry 只由用户点击触发;retryStatus 支持 idle/checking/denied/error/restored,checking 禁用重复检查,denied 保留原授权引导而不追加重复提示,
restored 只展示恢复结果,不重放导出/保存/删除。宿主刷新权限和授权后 Schema,再决定是否读取数据或允许用户重新操作。
只撤销记录读取权限时,由宿主清空旧行数据并把 inline 提示放在数据区,保留已授权表头和导航。
新增样式都同时限定在 .make-app-error-notice.make-app-error-notice--permission,不会改变原错误卡片。
可在新组件根节点通过 style/className 设置 --make-app-permission-primary、
--make-app-permission-primary-hover、--make-app-permission-text 和 --make-app-permission-muted。
本地视觉示例:先 pnpm build,再 pnpm dev,打开 /examples/permission-notice/。
示例通过公开包入口加载构建产物,用夹具演示三种样式、管理员和刷新状态,可与原错误卡片共同展示;不请求真实 IAM。
