diff --git a/src/pages/Replay/PluginPanel/components/StoragePanel/index.tsx b/src/pages/Replay/PluginPanel/components/StoragePanel/index.tsx index e3f44b02..11d74c7f 100644 --- a/src/pages/Replay/PluginPanel/components/StoragePanel/index.tsx +++ b/src/pages/Replay/PluginPanel/components/StoragePanel/index.tsx @@ -1,37 +1,67 @@ import Icon from '@ant-design/icons'; import { SpyStorage } from '@huolala-tech/page-spy-types'; import { Layout, Menu } from 'antd'; -import { memo, useState } from 'react'; +import { memo, useMemo, useState } from 'react'; import { ReactComponent as StorageSvg } from '@/assets/image/storage.svg'; import { ReactComponent as CookieSvg } from '@/assets/image/cookie.svg'; import { StorageContent } from './StorageContent'; import './index.less'; import { ResizableDetail } from '@/components/ResizableDetail'; +import { useReplayStore } from '@/store/replay'; +import { useShallow } from 'zustand/react/shallow'; +import { + isMiniProgram, + isReactNative, + isUniAppNative, +} from '@/store/platform-config'; const { Sider, Content } = Layout; -const storageMenus = [ - { - key: 'localStorage', - label: 'Local Storage', - icon: , - }, - { - key: 'sessionStorage', - label: 'Session Storage', - icon: , - }, - { - key: 'cookie', - label: 'Cookies', - icon: , - }, -]; - export const StoragePanel = memo(() => { const [activeTab, setActiveTab] = useState('localStorage'); + const clientInfo = useReplayStore(useShallow((state) => state.clientInfo)); + + const storageMenus = useMemo(() => { + const menus = [ + { + key: 'localStorage', + label: 'Local Storage', + icon: , + }, + { + key: 'sessionStorage', + label: 'Session Storage', + icon: , + }, + { + key: 'cookie', + label: 'Cookies', + icon: , + }, + ]; + const browserType = clientInfo?.browser.type || 'unknown'; + if (isMiniProgram(browserType) || isUniAppNative(browserType)) { + menus.splice(0); + menus.push({ + key: 'mpStorage', + label: '小程序 Storage', + icon: , + }); + } else if (isReactNative(browserType)) { + menus.splice(0); + menus.push({ + key: 'asyncStorage', + label: 'Async Storage', + icon: , + }); + } + + setActiveTab(menus[0].key as SpyStorage.DataType); + return menus; + }, [clientInfo?.browser.type]); + return (
diff --git a/src/pages/Replay/index.tsx b/src/pages/Replay/index.tsx index 93efca11..3c258b6d 100644 --- a/src/pages/Replay/index.tsx +++ b/src/pages/Replay/index.tsx @@ -32,7 +32,12 @@ const Replay = () => { const result = res.map((i: any) => { return { ...i, - data: JSON.parse(strFromU8(unzlibSync(strToU8(i.data, true)))), + // if string, it's compressed by zlib + // or it will be plain object. because in mp env, zlib is not available + data: + typeof i.data === 'string' + ? JSON.parse(strFromU8(unzlibSync(strToU8(i.data, true)))) + : i.data, }; }) as HarborDataItem[]; setAllData(result); diff --git a/src/store/replay.ts b/src/store/replay.ts index 6cda6ef8..2d4e5881 100644 --- a/src/store/replay.ts +++ b/src/store/replay.ts @@ -1,5 +1,6 @@ /* eslint-disable no-implicit-coercion */ import { + SpyClient, SpyConsole, SpyMessage, SpyStorage, @@ -15,6 +16,7 @@ import { ResolvedNetworkInfo, resolveUrlInfo, } from '@/utils'; +import { parseClientInfo, ParsedClientInfo } from '@/utils/brand'; import { DataType } from '@huolala-tech/page-spy-plugin-data-harbor/dist/types/harbor/base'; const isCaredActivity = (activity: HarborDataItem) => { @@ -46,14 +48,13 @@ export interface HarborDataItem { data: T; } -export interface MetaInfo { - ua?: string; +export type MetaInfo = { title?: string; url?: string; remark?: string; startTime?: number; endTime?: number; -} +} & SpyClient.DataItem; const isMetaInfo = (data: HarborDataItem): data is HarborDataItem => { return data.type === 'meta'; @@ -71,6 +72,7 @@ export interface ReplayStore { rrwebStartTime: number; setRRWebStartTime: (timestamp: number) => void; activity: Activity[]; + clientInfo: ParsedClientInfo | null; allConsoleMsg: HarborDataItem[]; allNetworkMsg: HarborDataItem[]; allRRwebEvent: eventWithTime[]; @@ -123,6 +125,7 @@ export const useReplayStore = create((set, get) => ({ ); }, activity: [], + clientInfo: null, allConsoleMsg: [], allNetworkMsg: [], allRRwebEvent: [], @@ -149,6 +152,7 @@ export const useReplayStore = create((set, get) => ({ let end = data[data.length - 1].timestamp; const lastData = data[data.length - 1]; + if (isMetaInfo(lastData)) { set( produce((state) => { @@ -156,8 +160,17 @@ export const useReplayStore = create((set, get) => ({ }), ); const { data } = lastData; - data.startTime && (start = data.startTime); - data.endTime && (end = data.endTime); + if (data.startTime && data.endTime) { + data.startTime && (start = data.startTime); + data.endTime && (end = data.endTime); + } + if (data.ua) { + set( + produce((state) => { + state.clientInfo = parseClientInfo(data); + }), + ); + } } const duration = end - start; @@ -171,6 +184,7 @@ export const useReplayStore = create((set, get) => ({ | 'allRRwebEvent' | 'allStorageMsg' | 'allSystemMsg' + | 'clientInfo' > = { activity: [], allConsoleMsg: [], @@ -178,6 +192,7 @@ export const useReplayStore = create((set, get) => ({ allRRwebEvent: [], allStorageMsg: [], allSystemMsg: [], + clientInfo: null, }; const { activity, @@ -186,6 +201,7 @@ export const useReplayStore = create((set, get) => ({ allRRwebEvent, allSystemMsg, allStorageMsg, + clientInfo, } = data.reduce((acc, cur) => { const { type, data, timestamp } = cur; if (timestamp < start) { @@ -241,6 +257,7 @@ export const useReplayStore = create((set, get) => ({ set( produce((state) => { state.activity = activity; + state.clientInfo = clientInfo; state.allConsoleMsg = allConsoleMsg; state.allNetworkMsg = allNetworkMsg; state.allRRwebEvent = allRRwebEvent;