('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;