diff --git a/package.json b/package.json index 1820bae5..6d9200f1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "private": true, - "version": "1.9.5", + "version": "1.9.6", "description": "All-In-One Remote Debugging Tool", "homepage": "https://huolalatech.github.io/page-spy-web", "repository": { @@ -50,10 +50,10 @@ }, "dependencies": { "@ant-design/icons": "^4.7.0", - "@huolala-tech/page-spy-browser": "^1.9.12", - "@huolala-tech/page-spy-plugin-data-harbor": "^1.3.10", + "@huolala-tech/page-spy-browser": "^1.9.13", + "@huolala-tech/page-spy-plugin-data-harbor": "^1.3.11", "@huolala-tech/page-spy-plugin-rrweb": "^1.2.7", - "@huolala-tech/page-spy-plugin-whole-bundle": "^0.0.8", + "@huolala-tech/page-spy-plugin-whole-bundle": "^0.0.9", "@huolala-tech/page-spy-types": "^1.9.6", "@huolala-tech/react-json-view": "^1.2.5", "@huolala-tech/request": "^1.1.2", diff --git a/src/assets/locales/en.json b/src/assets/locales/en.json index ab55b088..c521315a 100644 --- a/src/assets/locales/en.json +++ b/src/assets/locales/en.json @@ -233,7 +233,7 @@ "speed": "Speed", "delete-select": "Delete Selected", "delete-select-desc": "Are you sure you want to delete selected logs?", - "unsupport-spread": "Cannot spread object in offline mode" + "unsupport-spread": "<0>Objects cannot be expanded by default. Set <1><0>serializeData: true to enable." }, "lab": { "welcome": "Welcome to the Replay Lab!", diff --git a/src/assets/locales/ja.json b/src/assets/locales/ja.json index dfb69bd5..056f5525 100644 --- a/src/assets/locales/ja.json +++ b/src/assets/locales/ja.json @@ -232,7 +232,7 @@ "speed": "倍速", "delete-select": "選択されたものを削除", "delete-select-desc": "選択したログを削除してもよろしいですか?", - "unsupport-spread": "オフラインモードではオブジェクトを展開できません" + "unsupport-spread": "<0>デフォルトではオブジェクトを展開できません。<1><0>serializeData: true を設定して有効にします。" }, "lab": { "welcome": "リプレイラボへようこそ!", diff --git a/src/assets/locales/ko.json b/src/assets/locales/ko.json index 6cb65887..671a0c01 100644 --- a/src/assets/locales/ko.json +++ b/src/assets/locales/ko.json @@ -232,7 +232,7 @@ "speed": "속도", "delete-select": "선택 항목 삭제", "delete-select-desc": "선택한 로그를 삭제하시겠습니까?", - "unsupport-spread": "오프라인 모드에서는 객체를 펼칠 수 없습니다" + "unsupport-spread": "<0>기본적으로 객체를 확장할 수 없습니다. <1><0>serializeData: true 을 설정하여 활성화하십시오." }, "lab": { "welcome": "리플레이 실험실에 오신 것을 환영합니다!", diff --git a/src/assets/locales/zh.json b/src/assets/locales/zh.json index 4592c321..75a35699 100644 --- a/src/assets/locales/zh.json +++ b/src/assets/locales/zh.json @@ -232,7 +232,7 @@ "speed": "倍速", "delete-select": "删除已选", "delete-select-desc": "确认删除所有已选择的日志吗?", - "unsupport-spread": "离线模式无法展开对象" + "unsupport-spread": "<0>默认无法展开对象,设置 <1><0>serializeData: true 以启用。" }, "lab": { "welcome": "欢迎来到回放实验室!", diff --git a/src/components/ConsoleNode/index.tsx b/src/components/ConsoleNode/index.tsx index 67ed80b0..df037560 100644 --- a/src/components/ConsoleNode/index.tsx +++ b/src/components/ConsoleNode/index.tsx @@ -10,7 +10,7 @@ import { LoadMore } from './LoadMore'; import { useSocketMessageStore } from '@/store/socket-message'; import { useConfig } from '../ConfigProvider'; import { Tooltip } from 'antd'; -import { useTranslation } from 'react-i18next'; +import { Trans, useTranslation } from 'react-i18next'; function isAtomNode(data: SpyAtom.Overview) { return data && data.type === 'atom' && data.__atomId !== undefined; @@ -227,7 +227,24 @@ function AtomNode({ id, value, showArrow = true }: AtomNodeProps) { disabled: offline, })} > - + +

+ Objects cannot be expanded by default. Set + + serializeData: true + + to enable. +

+ + ) + } + > {showArrow && ( { - const { getData, requestPayload } = data; + const { getData, requestPayload, requestHeader } = data; + const isFormUrlencoded = requestHeader?.some(([name, value]) => { + if ( + name.toLowerCase() === 'content-type' && + value.includes('application/x-www-form-urlencoded') + ) + return true; + return false; + }); + return ( <> {/* Request Payload */} {!!requestPayload?.length && ( - + )} {/* Query String Parametes */} diff --git a/src/components/NetworkTable/RequestPayloadBlock/index.tsx b/src/components/NetworkTable/RequestPayloadBlock/index.tsx index c399fd04..545db507 100644 --- a/src/components/NetworkTable/RequestPayloadBlock/index.tsx +++ b/src/components/NetworkTable/RequestPayloadBlock/index.tsx @@ -5,13 +5,18 @@ import { EntriesBody } from '@/components/EntriesBody'; export const RequestPayloadBlock: React.FC<{ data: string | [string, string][]; -}> = ({ data }) => { + urlencoded?: boolean; +}> = ({ data, urlencoded = false }) => { const content = useMemo(() => { if (isString(data)) { + if (urlencoded) { + const params = new URLSearchParams(data); + return ; + } return ; } return ; - }, [data]); + }, [data, urlencoded]); return (
Request Payload diff --git a/src/pages/Docs/md/api.en.mdx b/src/pages/Docs/md/api.en.mdx index 60e20141..e5578735 100644 --- a/src/pages/Docs/md/api.en.mdx +++ b/src/pages/Docs/md/api.en.mdx @@ -19,6 +19,9 @@ - [constructor()](./data-harbor#constructor) - [$harbor.onOfflineLog()](./data-harbor#onOfflineLog) +- [$harbor.pause()](./data-harbor#pause) +- [$harbor.resume()](./data-harbor#resume) +- [$harbor.reharbor()](./data-harbor#reharbor) #### RRWebPlugin#rrweb diff --git a/src/pages/Docs/md/api.zh.mdx b/src/pages/Docs/md/api.zh.mdx index eb56730b..624ed6d7 100644 --- a/src/pages/Docs/md/api.zh.mdx +++ b/src/pages/Docs/md/api.zh.mdx @@ -19,6 +19,9 @@ - [constructor()](./data-harbor#constructor) - [$harbor.onOfflineLog()](./data-harbor#onOfflineLog) +- [$harbor.pause()](./data-harbor#pause) +- [$harbor.resume()](./data-harbor#resume) +- [$harbor.reharbor()](./data-harbor#reharbor) #### RRWebPlugin#rrweb diff --git a/src/pages/Docs/md/changelog.en.mdx b/src/pages/Docs/md/changelog.en.mdx index 2ff51929..0562778f 100644 --- a/src/pages/Docs/md/changelog.en.mdx +++ b/src/pages/Docs/md/changelog.en.mdx @@ -1,5 +1,14 @@ import offlineLogImg from '@/assets/image/screenshot/v1.9.2-offline-log-size.png'; +## v1.9.6 + +- 🆕 DataHarborPlugin added a new prototype method. See details: https://github.com/HuolalaTech/page-spy/pull/110; + - `$harbor.pause()`: Pause recording; + - `$harbor.resume()`: Resume recording, corresponding to `pause()`; + - `$harbor.reharbor()`: Clear the recorded data and remakes it. +- 🆕 Add new prompt for "Object cannot be expanded" on the replay page; +- 🐛 Fixed the display of `application/x-www-form-urlencoded` payload. See details: https://github.com/HuolalaTech/page-spy-web/issues/267; + ## v1.9.5 - 🆕 Add DockerHub image: https://hub.docker.com/r/huolalatech/page-spy-web; diff --git a/src/pages/Docs/md/changelog.zh.mdx b/src/pages/Docs/md/changelog.zh.mdx index 3c676bf5..f4e5a218 100644 --- a/src/pages/Docs/md/changelog.zh.mdx +++ b/src/pages/Docs/md/changelog.zh.mdx @@ -1,5 +1,14 @@ import offlineLogImg from '@/assets/image/screenshot/v1.9.2-offline-log-size.png'; +## v1.9.6 + +- 🆕 DataHarborPlugin 插件新增原型方法。查看详情:https://github.com/HuolalaTech/page-spy/pull/110 ; + - `$harbor.pause()`:暂停记录; + - `$harbor.resume()`: 恢复记录,和 `pause()` 对应; + - `$harbor.reharbor()`:清空已记录的数据并重新制作。 +- 🆕 回放页面对于「对象不可展开」新增提示; +- 🐛 修复 `application/x-www-form-urlencoded` 展示的 Payload。查看详情:https://github.com/HuolalaTech/page-spy-web/issues/267 ; + ## v1.9.5 - 🆕 新增 DockerHub 镜像: https://hub.docker.com/r/huolalatech/page-spy-web; diff --git a/src/pages/Docs/md/data-harbor.en.mdx b/src/pages/Docs/md/data-harbor.en.mdx index 02e784d2..1569da6e 100644 --- a/src/pages/Docs/md/data-harbor.en.mdx +++ b/src/pages/Docs/md/data-harbor.en.mdx @@ -11,7 +11,7 @@ // Default 10MB. maximum?: number; - // Specit which types of data to cache + // Specify which types of data to cache caredData?: Record; // Specify the offline log filename, with the default being named according to the current time @@ -21,39 +21,123 @@ onDownload?: (data: CacheMessageItem[]) => void; } - delcare class DataHarborPlugin implements PageSpyPlugin { + declare class DataHarborPlugin implements PageSpyPlugin { constructor(config?: DataHarborConfig); } ``` + #### onOfflineLog()#onOfflineLog -Upload / download log manaually. +Manually download / upload offline logs. - Type ```ts declare class DataHarborPlugin { - onOfflineLog(type: 'download' | 'upload'): Promise; + onOfflineLog(type: 'download' | 'upload', clearCache?: boolean): Promise; } ``` -- Details - - If you hide the automatically rendered floating or want to automatically trigger offline log operations at certain times, you can achieve through this method. - - Each invocation logs the entire current session. Once the upload is complete, a replay URL will be returned. + If you hide the automatically rendered UI controls by `autoRender: false`, or you want to automatically trigger the offline log operation at certain times, you can use this method. + After each call, the recorded log data will be cleared by default and recording will be restarted; on the contrary, if the user upload / download the log multiple times through the buttons on the UI dialog, it will be a complete log from beginning to end of the current session. You can also control it yourself through the second parameter `clearCache: boolean`. + + After the upload is completed, the replay URL will be returned and printed to the console. + - Example ```ts + - details window.$harbor = new DataHarborPlugin(); - // upload + // Upload (clear existing data and re-record) const url = await window.$harbor.onOfflineLog('upload'); + // Upload (do not clear data) + const url = await window.$harbor.onOfflineLog('upload', false); + // download window.$harbor.onOfflineLog('download'); ``` +#### pause()#pause + +Pause recording. + +- Type + + ```ts + declare class DataHarborPlugin { + pause(): void; + } + ``` + + More flexible control of logging behavior. + + The data generated by the program after the pause will not be recorded. Call `$harbor.resume()` to resume. + +- Example + + ```ts + window.$harbor = new DataHarborPlugin(); + + // pause + window.$harbor.pause(); + + // resume + window.$harbor.resume(); + ``` + + +#### resume()#resume + + +Resume records. + +- Type + + ```ts + declare class DataHarborPlugin { + resume(): void; + } + ``` + + More flexible control of logging behavior. + +- Details + + Data during <Pause - Resume> will not be recorded. + +- Example + + ```ts + window.$harbor = new DataHarborPlugin(); + + // pause + window.$harbor.pause(); + + // resume + window.$harbor.resume(); + ``` + +#### reharbor()#reharbor + +Clear the recorded data and continue recording. In short, remastered. + +- Type + + ```ts + declare class DataHarborPlugin { + reharbor(): void; + } + ``` + +- Example + + ```ts + window.$harbor = new DataHarborPlugin(); + + window.$harbor.reharbor(); + ``` \ No newline at end of file diff --git a/src/pages/Docs/md/data-harbor.zh.mdx b/src/pages/Docs/md/data-harbor.zh.mdx index ba9c8bbd..d3e39514 100644 --- a/src/pages/Docs/md/data-harbor.zh.mdx +++ b/src/pages/Docs/md/data-harbor.zh.mdx @@ -21,13 +21,12 @@ onDownload?: (data: CacheMessageItem[]) => void; } - delcare class DataHarborPlugin implements PageSpyPlugin { + declare class DataHarborPlugin implements PageSpyPlugin { constructor(config?: DataHarborConfig); } ``` - #### onOfflineLog()#onOfflineLog 手动操作离线日志的下载、上传。 @@ -36,7 +35,7 @@ ```ts declare class DataHarborPlugin { - onOfflineLog(type: 'download' | 'upload'): Promise; + onOfflineLog(type: 'download' | 'upload', clearCache?: boolean): Promise; } ``` @@ -44,18 +43,106 @@ 如果隐藏了自动渲染的 UI 控件,或者希望在某些时候自动触发队离线日志的操作,可以通过该方法实现。 - 每次调用都是当前会话的完整日志。上传完成后会返回回放的 URL,并打印到控制台。 + 每次调用后,默认会清除已记录的日志数据、并重新开始记录;与之相反,用户通过 UI 弹窗上的按钮操作日志上传 / 下载多次都是当前会话从头到尾的完整日志。你也可以通过第二个参数 `clearCache: boolean` 自行控制。 + + 上传完成后会返回回放的 URL,并打印到控制台。 - 示例 ```ts window.$harbor = new DataHarborPlugin(); - // 上传 + // 上传(清除已有数据、并重新记录) const url = await window.$harbor.onOfflineLog('upload'); + // 上传(不清除数据) + const url = await window.$harbor.onOfflineLog('upload', false); + // 下载 window.$harbor.onOfflineLog('download'); ``` +#### pause()#pause + +暂停记录。 + +- 类型 + + ```ts + declare class DataHarborPlugin { + pause(): void; + } + ``` + +- 详细信息 + + 更加灵活的控制记录日志的行为。 + + 暂停后程序产生的数据不会被记录,执行 `$harbor.resume()` 恢复。 + +- 示例 + + ```ts + window.$harbor = new DataHarborPlugin(); + + // 暂停 + window.$harbor.pause(); + + // 恢复 + window.$harbor.resume(); + ``` + + +#### resume()#resume + +恢复记录。 + +- 类型 + + ```ts + declare class DataHarborPlugin { + resume(): void; + } + ``` + +- 详细信息 + + 更加灵活的控制记录日志的行为。 + + <暂停 - 恢复> 期间的数据不会被记录。 + +- 示例 + + ```ts + window.$harbor = new DataHarborPlugin(); + + // 暂停 + window.$harbor.pause(); + + // 恢复 + window.$harbor.resume(); + ``` + + +#### reharbor()#reharbor + +清空已记录的数据,并继续记录。简而言之,重新制作。 + +- 类型 + + ```ts + declare class DataHarborPlugin { + reharbor(): void; + } + ``` + +- 示例 + + ```ts + window.$harbor = new DataHarborPlugin(); + + window.$harbor.reharbor(); + ``` + + diff --git a/src/pages/Replay/PluginPanel/index.tsx b/src/pages/Replay/PluginPanel/index.tsx index 43a0016d..93493c0a 100644 --- a/src/pages/Replay/PluginPanel/index.tsx +++ b/src/pages/Replay/PluginPanel/index.tsx @@ -28,7 +28,7 @@ export const PluginPanel = memo(() => { align="middle" style={{ paddingRight: 16, borderBottom: '1px solid rgb(5 5 5 / 6%)' }} > - + {Active.Extra && } diff --git a/yarn.lock b/yarn.lock index b72bf47a..90b7f025 100644 --- a/yarn.lock +++ b/yarn.lock @@ -742,20 +742,20 @@ dependencies: "@huolala-tech/page-spy-types" "^1.9.6" -"@huolala-tech/page-spy-browser@^1.9.12": - version "1.9.12" - resolved "https://registry.yarnpkg.com/@huolala-tech/page-spy-browser/-/page-spy-browser-1.9.12.tgz#4585c651c9953d9cc006510eaf29a9c5e7220f03" - integrity sha512-ko34sKFgerPN61yIG8C+XXc4otlLKNSWpJoHYPlj9pFkj00UxNSM1Bya+sduRLTw2nSv+3QZYLDOpJf4k0xJag== +"@huolala-tech/page-spy-browser@^1.9.13": + version "1.9.13" + resolved "https://registry.yarnpkg.com/@huolala-tech/page-spy-browser/-/page-spy-browser-1.9.13.tgz#33975e10716590b99cfe6074ebc00ca5e6e227ab" + integrity sha512-Bb6Vz3lZaaH9Ko36xm9jxKCdPHysk27k2uL+5jlqZ/x03ecqTAcrpHfKt7oBqbUXYLLaWyYydXr8OQ6s8rtvvg== dependencies: "@babel/runtime" "^7.13.0" "@huolala-tech/page-spy-base" "^1.0.6" "@huolala-tech/page-spy-types" "^1.9.6" copy-to-clipboard "^3.3.1" -"@huolala-tech/page-spy-plugin-data-harbor@^1.3.10": - version "1.3.10" - resolved "https://registry.yarnpkg.com/@huolala-tech/page-spy-plugin-data-harbor/-/page-spy-plugin-data-harbor-1.3.10.tgz#19a40eb8ed4971eff8e48abea85a8b7b3604bed4" - integrity sha512-XEbkjEYZsQYpKtpcwQS3l+WOJGn5EFCNlW0v/++T8Ampq73GM8jGJeoO6x6w3Qsix5hN9KGs7SOvGLt/fGlp6g== +"@huolala-tech/page-spy-plugin-data-harbor@^1.3.11": + version "1.3.11" + resolved "https://registry.yarnpkg.com/@huolala-tech/page-spy-plugin-data-harbor/-/page-spy-plugin-data-harbor-1.3.11.tgz#9745e0a5b278fffd4f1929a3dbbfa84ff17f589a" + integrity sha512-O8+MsV13QA+poKxUas/YQNFI9nImEKE6yCrQAqclq+qs/GkQaZluYpiEEkbONSQ8Umxq8ERW1Pxh81aCOcouWw== dependencies: "@babel/runtime" "^7.13.0" "@huolala-tech/page-spy-base" "^1.0.6" @@ -771,13 +771,13 @@ "@huolala-tech/page-spy-types" "^1.9.6" rrweb "^2.0.0-alpha.4" -"@huolala-tech/page-spy-plugin-whole-bundle@^0.0.8": - version "0.0.8" - resolved "https://registry.yarnpkg.com/@huolala-tech/page-spy-plugin-whole-bundle/-/page-spy-plugin-whole-bundle-0.0.8.tgz#c829e445eb36445c1a9dc9849ef644e0f3488fdb" - integrity sha512-vu0Wyui6/RpQ9VNtmuHYzQtF5BafxhErobYisRRwd5IPGnBMBf0p0eia0tw+T50QKa/dizj6Qs0ojZ6pmtqgLA== +"@huolala-tech/page-spy-plugin-whole-bundle@^0.0.9": + version "0.0.9" + resolved "https://registry.yarnpkg.com/@huolala-tech/page-spy-plugin-whole-bundle/-/page-spy-plugin-whole-bundle-0.0.9.tgz#c2137b06dc236c082a825835054f6e4dcb53c404" + integrity sha512-rZFVf1gTwgSLUHmbX6DmukGPHS0Vz+CiCe4bs2rSdl1qC94wfoGKhGLEtWfi3hQdZqkub9+4EJVdyKlDu3S8/A== dependencies: - "@huolala-tech/page-spy-browser" "^1.9.12" - "@huolala-tech/page-spy-plugin-data-harbor" "^1.3.10" + "@huolala-tech/page-spy-browser" "^1.9.13" + "@huolala-tech/page-spy-plugin-data-harbor" "^1.3.11" "@huolala-tech/page-spy-plugin-rrweb" "^1.2.7" "@huolala-tech/page-spy-types@^1.9.6":