修复桌面端会话内错误提示完全不可见、收藏发送面板显示空白/裸类型名、delivery-marker图标className拼出undefined
- 桌面布局下打开一个会话时,sidepanel-view.jsx 走的是 messages-home 分支(渲染
MessageCenterView),这个分支从来没有渲染过ErrorPanel;messages-view.jsx自己的ErrorPanel
又只在displayMobile时才渲染——两边一凑,桌面端(最常见的使用状态)里任何onError(...)调用
(上传失败、收藏转发失败、URL风控拦截等)全部没有可见的展示出口,用户只会觉得"点了但什么
反应都没有"。已用真实handleError()调用实测确认:修复前DOM里根本没有.info-box节点,修复后
正确渲染且visible。
- "我的收藏"发送面板:favoriteSummary()对图片/视频收藏显示空白(真实数据里这两类的
snapshot.content.txt是占位用的单个空格,被直接当文本展示)、对文本类收藏显示裸露的内部
类型字符串"text"(FAVORITE_TYPE_LABEL没有text这个key,且文本收藏的content本身就是纯字符串
而非{txt:...}对象,原逻辑没处理这种形状)。改成图片/视频/语音三类固定用类型标签、文本类型
优先判断content本身是不是纯字符串、并给FAVORITE_TYPE_LABEL补上text条目。
- received-marker.jsx的已发送/已送达图标(deliveryMarker对这两种状态返回的对象没有color字段)
拼接className时把undefined直接字符串化拼了进去,实际渲染成"material-icons small undefined"。
均已重新构建验证;received-marker/favoriteSummary为纯函数级修复,逻辑经过仔细核对但未逐一
截图复核(不依赖运行时状态,风险低)。
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 5
parent
47148aa75d
commit
38b43936ce
@@ -164,6 +164,17 @@ class SidepanelView extends React.PureComponent {
|
|||||||
myUserId={this.props.myUserId}
|
myUserId={this.props.myUserId}
|
||||||
onTopicSelected={this.props.onTopicSelected}
|
onTopicSelected={this.props.onTopicSelected}
|
||||||
onOpenScanner={this.props.onOpenScanner} />
|
onOpenScanner={this.props.onOpenScanner} />
|
||||||
|
{/* This branch never rendered ErrorPanel at all -- on desktop (non-mobile), opening a real
|
||||||
|
conversation lands here (view stays 'messages-home' behind the split-view topic pane),
|
||||||
|
and messages-view.jsx's own ErrorPanel is only rendered on displayMobile. Every
|
||||||
|
this.props.onError(...) call reachable from an open conversation on desktop (failed
|
||||||
|
uploads, failed forwards, URL risk blocks, etc.) had no visible outlet at all. */}
|
||||||
|
<ErrorPanel
|
||||||
|
level={this.props.errorLevel}
|
||||||
|
text={this.props.errorText}
|
||||||
|
action={this.props.errorAction}
|
||||||
|
actionText={this.props.errorActionText}
|
||||||
|
onClearError={this.props.onError} />
|
||||||
</div>;
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,7 +38,10 @@ class ReceivedMarker extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const icon = deliveryMarker(this.props.received);
|
const icon = deliveryMarker(this.props.received);
|
||||||
const marker = icon ? <i className={'material-icons small ' + icon.color}>{icon.name}</i> : null;
|
// icon.color is only set for the failed/read cases (deliveryMarker's other {name} results omit
|
||||||
|
// the key entirely) -- string-concatenating it unconditionally put the literal text "undefined"
|
||||||
|
// into the className for sending/sent/received messages.
|
||||||
|
const marker = icon ? <i className={'material-icons small ' + (icon.color || '')}>{icon.name}</i> : null;
|
||||||
const edited = this.props.edited ? formatMessage(messages.message_edited_marker) : null;
|
const edited = this.props.edited ? formatMessage(messages.message_edited_marker) : null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -30,12 +30,20 @@ const EMOJI_LIST = ['😀', '😁', '😂', '🤣', '😃', '😄', '😅', '
|
|||||||
// 互相 import,就近各自维护一份小常量)。收藏摘要要优先读 snapshot.content.txt 这个结构化字段,
|
// 互相 import,就近各自维护一份小常量)。收藏摘要要优先读 snapshot.content.txt 这个结构化字段,
|
||||||
// 不能像最初那版一样直接展示 snapshot.text——那是整条 content 原样 JSON.stringify 的结果
|
// 不能像最初那版一样直接展示 snapshot.text——那是整条 content 原样 JSON.stringify 的结果
|
||||||
// (例如 {"txt":"..."}),不是给人看的,之前联调时真被这个坑绊了一次才发现。
|
// (例如 {"txt":"..."}),不是给人看的,之前联调时真被这个坑绊了一次才发现。
|
||||||
const FAVORITE_TYPE_LABEL = {image: '[图片]', video: '[视频]', voice: '[语音]', file: '[文件]', link: '[链接]'};
|
const FAVORITE_TYPE_LABEL = {image: '[图片]', video: '[视频]', voice: '[语音]', file: '[文件]', link: '[链接]', text: '[文本]'};
|
||||||
function favoriteSummary(item) {
|
function favoriteSummary(item) {
|
||||||
const content = item.snapshot && item.snapshot.content;
|
// image/video/voice favorites' snapshot.content.txt is a placeholder single space in this
|
||||||
if (content && typeof content.txt === 'string' && content.txt) {
|
// project's convention (confirmed via a real GET /favorites response) -- reading it as the
|
||||||
return content.txt;
|
// summary showed a blank line instead of a type label for these three types.
|
||||||
|
if (item.type === 'image' || item.type === 'video' || item.type === 'voice') {
|
||||||
|
return FAVORITE_TYPE_LABEL[item.type];
|
||||||
}
|
}
|
||||||
|
const content = item.snapshot && item.snapshot.content;
|
||||||
|
// A text favorite's snapshot.content is a plain string, not a {txt:...} Drafty object --
|
||||||
|
// content.txt on it is undefined, which used to fall through all the way to the internal
|
||||||
|
// item.type value ("text") being shown to the user verbatim.
|
||||||
|
if (typeof content === 'string' && content.trim()) return content;
|
||||||
|
if (content && typeof content.txt === 'string' && content.txt.trim()) return content.txt;
|
||||||
return FAVORITE_TYPE_LABEL[item.type] || item.type || item.favorite_id;
|
return FAVORITE_TYPE_LABEL[item.type] || item.type || item.favorite_id;
|
||||||
}
|
}
|
||||||
const RECENT_EMOJI_KEY = 'im-recent-emoji';
|
const RECENT_EMOJI_KEY = 'im-recent-emoji';
|
||||||
|
|||||||
+9
-3
@@ -17376,15 +17376,21 @@ class SidepanelView extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureCo
|
|||||||
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)("div", {
|
return (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)("div", {
|
||||||
id: "sidepanel",
|
id: "sidepanel",
|
||||||
className: 'message-center-panel' + (fullPage ? ' full-page' : ''),
|
className: 'message-center-panel' + (fullPage ? ' full-page' : ''),
|
||||||
children: (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_message_center_view_jsx__WEBPACK_IMPORTED_MODULE_7__["default"], {
|
children: [(0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_message_center_view_jsx__WEBPACK_IMPORTED_MODULE_7__["default"], {
|
||||||
view: view,
|
view: view,
|
||||||
connected: this.props.connected,
|
connected: this.props.connected,
|
||||||
chatList: this.props.chatList,
|
chatList: this.props.chatList,
|
||||||
myUserId: this.props.myUserId,
|
myUserId: this.props.myUserId,
|
||||||
onTopicSelected: this.props.onTopicSelected,
|
onTopicSelected: this.props.onTopicSelected,
|
||||||
onOpenScanner: this.props.onOpenScanner
|
onOpenScanner: this.props.onOpenScanner
|
||||||
}, view, false)
|
}, view, false), (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_25__.jsxDEV)(_widgets_error_panel_jsx__WEBPACK_IMPORTED_MODULE_2__["default"], {
|
||||||
}, void 0, false);
|
level: this.props.errorLevel,
|
||||||
|
text: this.props.errorText,
|
||||||
|
action: this.props.errorAction,
|
||||||
|
actionText: this.props.errorActionText,
|
||||||
|
onClearError: this.props.onError
|
||||||
|
}, void 0, false)]
|
||||||
|
}, void 0, true);
|
||||||
}
|
}
|
||||||
const chapterThreeViews = ['chat-inbound-request', 'chat-inbound-message', 'chat-outbound-request', 'chat-status', 'chat-friend', 'chat-media', 'chat-blocked', 'chat-deleted', 'chat-standard', 'chat-attachments', 'chat-mixed', 'chat-contact-card'];
|
const chapterThreeViews = ['chat-inbound-request', 'chat-inbound-message', 'chat-outbound-request', 'chat-status', 'chat-friend', 'chat-media', 'chat-blocked', 'chat-deleted', 'chat-standard', 'chat-attachments', 'chat-mixed', 'chat-contact-card'];
|
||||||
if (chapterThreeViews.includes(view)) {
|
if (chapterThreeViews.includes(view)) {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -3448,7 +3448,7 @@ class ReceivedMarker extends (react__WEBPACK_IMPORTED_MODULE_0___default().PureC
|
|||||||
}
|
}
|
||||||
const icon = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_3__.deliveryMarker)(this.props.received);
|
const icon = (0,_lib_utils_js__WEBPACK_IMPORTED_MODULE_3__.deliveryMarker)(this.props.received);
|
||||||
const marker = icon ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("i", {
|
const marker = icon ? (0,react_jsx_dev_runtime__WEBPACK_IMPORTED_MODULE_4__.jsxDEV)("i", {
|
||||||
className: 'material-icons small ' + icon.color,
|
className: 'material-icons small ' + (icon.color || ''),
|
||||||
children: icon.name
|
children: icon.name
|
||||||
}, void 0, false) : null;
|
}, void 0, false) : null;
|
||||||
const edited = this.props.edited ? formatMessage(messages.message_edited_marker) : null;
|
const edited = this.props.edited ? formatMessage(messages.message_edited_marker) : null;
|
||||||
@@ -3496,13 +3496,16 @@ const FAVORITE_TYPE_LABEL = {
|
|||||||
video: '[视频]',
|
video: '[视频]',
|
||||||
voice: '[语音]',
|
voice: '[语音]',
|
||||||
file: '[文件]',
|
file: '[文件]',
|
||||||
link: '[链接]'
|
link: '[链接]',
|
||||||
|
text: '[文本]'
|
||||||
};
|
};
|
||||||
function favoriteSummary(item) {
|
function favoriteSummary(item) {
|
||||||
const content = item.snapshot && item.snapshot.content;
|
if (item.type === 'image' || item.type === 'video' || item.type === 'voice') {
|
||||||
if (content && typeof content.txt === 'string' && content.txt) {
|
return FAVORITE_TYPE_LABEL[item.type];
|
||||||
return content.txt;
|
|
||||||
}
|
}
|
||||||
|
const content = item.snapshot && item.snapshot.content;
|
||||||
|
if (typeof content === 'string' && content.trim()) return content;
|
||||||
|
if (content && typeof content.txt === 'string' && content.txt.trim()) return content.txt;
|
||||||
return FAVORITE_TYPE_LABEL[item.type] || item.type || item.favorite_id;
|
return FAVORITE_TYPE_LABEL[item.type] || item.type || item.favorite_id;
|
||||||
}
|
}
|
||||||
const RECENT_EMOJI_KEY = 'im-recent-emoji';
|
const RECENT_EMOJI_KEY = 'im-recent-emoji';
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user