react-native-inapp-inspector 2.2.9 → 2.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commonjs/components/AppHeaderLogo.js +45 -12
- package/dist/commonjs/components/BrandSquareIcon.js +92 -49
- package/dist/commonjs/components/EmptyState.d.ts +7 -2
- package/dist/commonjs/components/EmptyState.js +11 -5
- package/dist/commonjs/components/Inspector/AnalyticsTab.js +29 -18
- package/dist/commonjs/components/Inspector/ConsoleTab.js +6 -1
- package/dist/commonjs/components/Inspector/CrashDetail.js +43 -9
- package/dist/commonjs/components/Inspector/CrashTab.js +34 -3
- package/dist/commonjs/components/Inspector/DeviceInfoTab.js +80 -16
- package/dist/commonjs/components/Inspector/InspectorHeader.js +16 -3
- package/dist/commonjs/components/Inspector/MainScreen.js +7 -11
- package/dist/commonjs/components/Inspector/NetworkDetail.js +3 -2
- package/dist/commonjs/components/Inspector/NetworkTab.js +103 -4
- package/dist/commonjs/components/Inspector/ReduxTab.js +19 -3
- package/dist/commonjs/components/Inspector/SettingsPanel.js +4 -4
- package/dist/commonjs/components/Inspector/StorageTab.js +123 -92
- package/dist/commonjs/components/JsonViewer.js +2 -0
- package/dist/commonjs/components/MetaAccordion.js +15 -3
- package/dist/commonjs/components/SkeletonPlaceholder.d.ts +6 -0
- package/dist/commonjs/components/SkeletonPlaceholder.js +208 -0
- package/dist/commonjs/constants/version.d.ts +1 -1
- package/dist/commonjs/constants/version.js +1 -1
- package/dist/commonjs/customHooks/networkLogger.d.ts +3 -0
- package/dist/commonjs/customHooks/networkLogger.js +10 -1
- package/dist/commonjs/customHooks/storageInspector.d.ts +2 -2
- package/dist/commonjs/customHooks/storageInspector.js +17 -13
- package/dist/commonjs/helpers/index.d.ts +6 -0
- package/dist/commonjs/helpers/index.js +196 -6
- package/dist/commonjs/helpers/searchQueryParser.js +62 -20
- package/dist/commonjs/i18n/index.d.ts +13 -0
- package/dist/commonjs/i18n/index.js +35 -2
- package/dist/commonjs/index.d.ts +3 -0
- package/dist/commonjs/index.js +108 -35
- package/dist/commonjs/styles/AppColors.d.ts +4 -0
- package/dist/commonjs/styles/AppColors.js +11 -1
- package/dist/commonjs/styles/AppFonts.d.ts +11 -0
- package/dist/commonjs/styles/AppFonts.js +11 -1
- package/dist/commonjs/types/interfaces.d.ts +2 -2
- package/dist/esm/components/AppHeaderLogo.js +45 -12
- package/dist/esm/components/BrandSquareIcon.js +92 -49
- package/dist/esm/components/EmptyState.d.ts +7 -2
- package/dist/esm/components/EmptyState.js +11 -5
- package/dist/esm/components/Inspector/AnalyticsTab.js +30 -19
- package/dist/esm/components/Inspector/ConsoleTab.js +6 -1
- package/dist/esm/components/Inspector/CrashDetail.js +43 -9
- package/dist/esm/components/Inspector/CrashTab.js +34 -3
- package/dist/esm/components/Inspector/DeviceInfoTab.js +80 -16
- package/dist/esm/components/Inspector/InspectorHeader.js +17 -4
- package/dist/esm/components/Inspector/MainScreen.js +8 -12
- package/dist/esm/components/Inspector/NetworkDetail.js +3 -2
- package/dist/esm/components/Inspector/NetworkTab.js +103 -4
- package/dist/esm/components/Inspector/ReduxTab.js +19 -3
- package/dist/esm/components/Inspector/SettingsPanel.js +4 -4
- package/dist/esm/components/Inspector/StorageTab.js +124 -93
- package/dist/esm/components/JsonViewer.js +2 -0
- package/dist/esm/components/MetaAccordion.js +15 -3
- package/dist/esm/components/SkeletonPlaceholder.d.ts +6 -0
- package/dist/esm/components/SkeletonPlaceholder.js +173 -0
- package/dist/esm/constants/version.d.ts +1 -1
- package/dist/esm/constants/version.js +1 -1
- package/dist/esm/customHooks/networkLogger.d.ts +3 -0
- package/dist/esm/customHooks/networkLogger.js +8 -0
- package/dist/esm/customHooks/storageInspector.d.ts +2 -2
- package/dist/esm/customHooks/storageInspector.js +17 -13
- package/dist/esm/helpers/index.d.ts +6 -0
- package/dist/esm/helpers/index.js +193 -5
- package/dist/esm/helpers/searchQueryParser.js +62 -20
- package/dist/esm/i18n/index.d.ts +13 -0
- package/dist/esm/i18n/index.js +33 -3
- package/dist/esm/index.d.ts +3 -0
- package/dist/esm/index.js +97 -37
- package/dist/esm/styles/AppColors.d.ts +4 -0
- package/dist/esm/styles/AppColors.js +9 -0
- package/dist/esm/styles/AppFonts.d.ts +11 -0
- package/dist/esm/styles/AppFonts.js +9 -0
- package/dist/esm/types/interfaces.d.ts +2 -2
- package/package.json +1 -1
- package/src/components/AppHeaderLogo.tsx +46 -12
- package/src/components/BrandSquareIcon.tsx +127 -78
- package/src/components/EmptyState.tsx +27 -5
- package/src/components/Inspector/AnalyticsTab.tsx +48 -27
- package/src/components/Inspector/ConsoleTab.tsx +10 -0
- package/src/components/Inspector/CrashDetail.tsx +65 -9
- package/src/components/Inspector/CrashTab.tsx +41 -3
- package/src/components/Inspector/DeviceInfoTab.tsx +87 -16
- package/src/components/Inspector/InspectorHeader.tsx +24 -4
- package/src/components/Inspector/MainScreen.tsx +7 -11
- package/src/components/Inspector/NetworkDetail.tsx +4 -4
- package/src/components/Inspector/NetworkTab.tsx +129 -4
- package/src/components/Inspector/ReduxTab.tsx +26 -8
- package/src/components/Inspector/SettingsPanel.tsx +4 -4
- package/src/components/Inspector/StorageTab.tsx +191 -117
- package/src/components/JsonViewer.tsx +2 -0
- package/src/components/MetaAccordion.tsx +18 -3
- package/src/components/SkeletonPlaceholder.tsx +206 -0
- package/src/constants/version.ts +1 -1
- package/src/customHooks/networkLogger.ts +15 -0
- package/src/customHooks/storageInspector.ts +18 -14
- package/src/helpers/index.ts +213 -5
- package/src/helpers/searchQueryParser.ts +63 -20
- package/src/i18n/index.ts +38 -3
- package/src/index.tsx +124 -37
- package/src/styles/AppColors.ts +9 -0
- package/src/styles/AppFonts.ts +16 -0
- package/src/types/interfaces.ts +2 -2
|
@@ -273,13 +273,13 @@ export const calculateByteSize = (str: string): number => {
|
|
|
273
273
|
};
|
|
274
274
|
|
|
275
275
|
/**
|
|
276
|
-
* Determine type and format value safely
|
|
276
|
+
* Determine type and format value safely without blocking JS thread
|
|
277
277
|
*/
|
|
278
278
|
export const analyzeStorageValue = (
|
|
279
279
|
rawVal: any,
|
|
280
280
|
): {
|
|
281
281
|
strVal: string;
|
|
282
|
-
|
|
282
|
+
parsedValue?: any;
|
|
283
283
|
type: 'json' | 'string' | 'number' | 'boolean' | 'null';
|
|
284
284
|
byteSize: number;
|
|
285
285
|
} => {
|
|
@@ -288,14 +288,14 @@ export const analyzeStorageValue = (
|
|
|
288
288
|
}
|
|
289
289
|
|
|
290
290
|
const strVal = typeof rawVal === 'string' ? rawVal : String(rawVal);
|
|
291
|
-
const byteSize =
|
|
291
|
+
const byteSize = strVal.length * 2;
|
|
292
292
|
|
|
293
293
|
if (typeof rawVal === 'number') {
|
|
294
|
-
return {strVal,
|
|
294
|
+
return {strVal, parsedValue: rawVal, type: 'number', byteSize};
|
|
295
295
|
}
|
|
296
296
|
|
|
297
297
|
if (typeof rawVal === 'boolean') {
|
|
298
|
-
return {strVal,
|
|
298
|
+
return {strVal, parsedValue: rawVal, type: 'boolean', byteSize};
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
const trimmed = strVal.trim();
|
|
@@ -303,18 +303,22 @@ export const analyzeStorageValue = (
|
|
|
303
303
|
(trimmed.startsWith('{') && trimmed.endsWith('}')) ||
|
|
304
304
|
(trimmed.startsWith('[') && trimmed.endsWith(']'))
|
|
305
305
|
) {
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
306
|
+
// For small/medium JSON, parse eagerly; for huge payloads (>10KB), parse lazily on expand
|
|
307
|
+
if (trimmed.length < 10000) {
|
|
308
|
+
try {
|
|
309
|
+
const parsed = JSON.parse(trimmed);
|
|
310
|
+
return {strVal, parsedValue: parsed, type: 'json', byteSize};
|
|
311
|
+
} catch {}
|
|
312
|
+
}
|
|
313
|
+
return {strVal, type: 'json', byteSize};
|
|
310
314
|
}
|
|
311
315
|
|
|
312
316
|
if (trimmed === 'true' || trimmed === 'false') {
|
|
313
|
-
return {strVal,
|
|
317
|
+
return {strVal, parsedValue: trimmed === 'true', type: 'boolean', byteSize};
|
|
314
318
|
}
|
|
315
319
|
|
|
316
320
|
if (!isNaN(Number(trimmed)) && trimmed !== '') {
|
|
317
|
-
return {strVal,
|
|
321
|
+
return {strVal, parsedValue: Number(trimmed), type: 'number', byteSize};
|
|
318
322
|
}
|
|
319
323
|
|
|
320
324
|
return {strVal, type: 'string', byteSize};
|
|
@@ -346,7 +350,7 @@ export const fetchStorageEntries = async (
|
|
|
346
350
|
entries.push({
|
|
347
351
|
key: k,
|
|
348
352
|
value: analysis.strVal,
|
|
349
|
-
parsedValue: analysis.
|
|
353
|
+
parsedValue: analysis.parsedValue,
|
|
350
354
|
type: analysis.type,
|
|
351
355
|
byteSize: analysis.byteSize,
|
|
352
356
|
});
|
|
@@ -358,7 +362,7 @@ export const fetchStorageEntries = async (
|
|
|
358
362
|
entries.push({
|
|
359
363
|
key: k,
|
|
360
364
|
value: analysis.strVal,
|
|
361
|
-
parsedValue: analysis.
|
|
365
|
+
parsedValue: analysis.parsedValue,
|
|
362
366
|
type: analysis.type,
|
|
363
367
|
byteSize: analysis.byteSize,
|
|
364
368
|
});
|
|
@@ -397,7 +401,7 @@ export const fetchStorageEntries = async (
|
|
|
397
401
|
entries.push({
|
|
398
402
|
key: k,
|
|
399
403
|
value: analysis.strVal,
|
|
400
|
-
parsedValue: analysis.
|
|
404
|
+
parsedValue: analysis.parsedValue,
|
|
401
405
|
type: analysis.type,
|
|
402
406
|
byteSize: analysis.byteSize,
|
|
403
407
|
});
|
package/src/helpers/index.ts
CHANGED
|
@@ -198,16 +198,37 @@ export const getNavigationInfo = (
|
|
|
198
198
|
state: any,
|
|
199
199
|
path: string[] = [],
|
|
200
200
|
): RouteInfo => {
|
|
201
|
-
if (!state
|
|
201
|
+
if (!state) {
|
|
202
202
|
return {
|
|
203
|
-
path: path.length > 0 ? path.join(' ➔ ') : '
|
|
203
|
+
path: path.length > 0 ? path.join(' ➔ ') : '',
|
|
204
204
|
params: null,
|
|
205
205
|
};
|
|
206
206
|
}
|
|
207
|
-
|
|
207
|
+
if (state.name && !state.routes) {
|
|
208
|
+
const fullPath =
|
|
209
|
+
path.length > 0 ? [...path, state.name].join(' ➔ ') : state.name;
|
|
210
|
+
return {path: fullPath, params: state.params || null};
|
|
211
|
+
}
|
|
212
|
+
if (
|
|
213
|
+
!state.routes ||
|
|
214
|
+
!Array.isArray(state.routes) ||
|
|
215
|
+
state.routes.length === 0
|
|
216
|
+
) {
|
|
217
|
+
return {
|
|
218
|
+
path: path.length > 0 ? path.join(' ➔ ') : '',
|
|
219
|
+
params: null,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
const index =
|
|
223
|
+
typeof state.index === 'number' &&
|
|
224
|
+
state.index >= 0 &&
|
|
225
|
+
state.index < state.routes.length
|
|
226
|
+
? state.index
|
|
227
|
+
: 0;
|
|
228
|
+
const route = state.routes[index];
|
|
208
229
|
if (!route) {
|
|
209
230
|
return {
|
|
210
|
-
path: path.length > 0 ? path.join(' ➔ ') : '
|
|
231
|
+
path: path.length > 0 ? path.join(' ➔ ') : '',
|
|
211
232
|
params: null,
|
|
212
233
|
};
|
|
213
234
|
}
|
|
@@ -217,10 +238,96 @@ export const getNavigationInfo = (
|
|
|
217
238
|
return getNavigationInfo(route.state, currentPath);
|
|
218
239
|
}
|
|
219
240
|
const resolved =
|
|
220
|
-
currentPath.length > 0 ? currentPath.join(' ➔ ') : '
|
|
241
|
+
currentPath.length > 0 ? currentPath.join(' ➔ ') : route.name || '';
|
|
221
242
|
return {path: resolved, params: route.params || null};
|
|
222
243
|
};
|
|
223
244
|
|
|
245
|
+
export const getLogPageName = (
|
|
246
|
+
log: NetworkLog,
|
|
247
|
+
routeInfo?: RouteInfo | null,
|
|
248
|
+
): string => {
|
|
249
|
+
// 1. If routeInfo has a valid path, resolve the leaf screen name
|
|
250
|
+
const effectiveRoute = routeInfo || (log as any)?.routeInfo;
|
|
251
|
+
if (
|
|
252
|
+
effectiveRoute &&
|
|
253
|
+
effectiveRoute.path &&
|
|
254
|
+
effectiveRoute.path !== 'Navigators'
|
|
255
|
+
) {
|
|
256
|
+
const parts = effectiveRoute.path
|
|
257
|
+
.split(' ➔ ')
|
|
258
|
+
.map((s: string) => s.trim())
|
|
259
|
+
.filter(Boolean);
|
|
260
|
+
if (parts.length > 0) {
|
|
261
|
+
return parts[parts.length - 1]; // Leaf screen name, e.g. "HomeScreen", "ProfileScreen"
|
|
262
|
+
}
|
|
263
|
+
return effectiveRoute.path;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// 2. Extract screen / component name from log.caller stack trace
|
|
267
|
+
if (log.caller && log.caller !== 'Unknown') {
|
|
268
|
+
try {
|
|
269
|
+
const match = log.caller.match(/([^/\\]+)\.(tsx|jsx|ts|js)/i);
|
|
270
|
+
if (match && match[1]) {
|
|
271
|
+
const file = match[1];
|
|
272
|
+
const ignored = [
|
|
273
|
+
'networklogger',
|
|
274
|
+
'fetch',
|
|
275
|
+
'axios',
|
|
276
|
+
'apiclient',
|
|
277
|
+
'request',
|
|
278
|
+
'http',
|
|
279
|
+
'index',
|
|
280
|
+
'nativeinspector',
|
|
281
|
+
'inappinspector',
|
|
282
|
+
'bundleanalyzer',
|
|
283
|
+
];
|
|
284
|
+
if (!ignored.includes(file.toLowerCase())) {
|
|
285
|
+
return file;
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
} catch (e) {}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// 3. Fallback to API resource / endpoint category from URL
|
|
292
|
+
if (log.url) {
|
|
293
|
+
try {
|
|
294
|
+
const cleanUrl = log.url.split('?')[0].split('#')[0];
|
|
295
|
+
const withoutProto = cleanUrl.replace(/^https?:\/\//i, '');
|
|
296
|
+
const slashIdx = withoutProto.indexOf('/');
|
|
297
|
+
if (slashIdx !== -1) {
|
|
298
|
+
const pathSegments = withoutProto
|
|
299
|
+
.substring(slashIdx + 1)
|
|
300
|
+
.split('/')
|
|
301
|
+
.filter(Boolean);
|
|
302
|
+
const ignoredSegments = [
|
|
303
|
+
'api',
|
|
304
|
+
'v1',
|
|
305
|
+
'v2',
|
|
306
|
+
'v3',
|
|
307
|
+
'v4',
|
|
308
|
+
'rest',
|
|
309
|
+
'graphql',
|
|
310
|
+
'json',
|
|
311
|
+
'data',
|
|
312
|
+
'service',
|
|
313
|
+
'app',
|
|
314
|
+
];
|
|
315
|
+
const meaningful = pathSegments.filter(
|
|
316
|
+
s => !ignoredSegments.includes(s.toLowerCase()),
|
|
317
|
+
);
|
|
318
|
+
if (meaningful.length > 0) {
|
|
319
|
+
const seg = meaningful[0];
|
|
320
|
+
return seg.charAt(0).toUpperCase() + seg.slice(1);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
const host = withoutProto.split('/')[0];
|
|
324
|
+
if (host) return host;
|
|
325
|
+
} catch (e) {}
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
return 'General';
|
|
329
|
+
};
|
|
330
|
+
|
|
224
331
|
export const flattenObject = (obj: any, prefix = ''): Record<string, any> => {
|
|
225
332
|
let result: Record<string, any> = {};
|
|
226
333
|
if (typeof obj === 'object' && obj !== null) {
|
|
@@ -409,6 +516,107 @@ export const getAppName = (): string => {
|
|
|
409
516
|
return 'App';
|
|
410
517
|
};
|
|
411
518
|
|
|
519
|
+
export const getAppVersionAndBuild = (): {
|
|
520
|
+
version: string;
|
|
521
|
+
build: string;
|
|
522
|
+
formatted: string;
|
|
523
|
+
} => {
|
|
524
|
+
let version = '';
|
|
525
|
+
let build = '';
|
|
526
|
+
|
|
527
|
+
// 1. Try ExpoApplication / ExponentConstants
|
|
528
|
+
const ExpoApplication = NativeModules.ExpoApplication;
|
|
529
|
+
if (ExpoApplication) {
|
|
530
|
+
if (typeof ExpoApplication.nativeAppVersion === 'string') {
|
|
531
|
+
version = ExpoApplication.nativeAppVersion;
|
|
532
|
+
}
|
|
533
|
+
if (typeof ExpoApplication.nativeBuildVersion === 'string') {
|
|
534
|
+
build = ExpoApplication.nativeBuildVersion;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
const ExponentConstants = NativeModules.ExponentConstants;
|
|
539
|
+
if (ExponentConstants) {
|
|
540
|
+
const manifest = ExponentConstants.manifest || ExponentConstants.expoConfig;
|
|
541
|
+
if (manifest) {
|
|
542
|
+
if (!version && manifest.version) {
|
|
543
|
+
version = String(manifest.version);
|
|
544
|
+
}
|
|
545
|
+
if (!build) {
|
|
546
|
+
if (manifest.ios?.buildNumber) {
|
|
547
|
+
build = String(manifest.ios.buildNumber);
|
|
548
|
+
} else if (manifest.android?.versionCode) {
|
|
549
|
+
build = String(manifest.android.versionCode);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
// 2. Try react-native-device-info
|
|
556
|
+
const RNDeviceInfo = NativeModules.RNDeviceInfo;
|
|
557
|
+
if (RNDeviceInfo) {
|
|
558
|
+
if (!version) {
|
|
559
|
+
if (typeof RNDeviceInfo.appVersion === 'string') {
|
|
560
|
+
version = RNDeviceInfo.appVersion;
|
|
561
|
+
} else if (typeof RNDeviceInfo.getVersion === 'function') {
|
|
562
|
+
try {
|
|
563
|
+
version = RNDeviceInfo.getVersion();
|
|
564
|
+
} catch (e) {}
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
if (!build) {
|
|
568
|
+
if (typeof RNDeviceInfo.buildNumber === 'string') {
|
|
569
|
+
build = RNDeviceInfo.buildNumber;
|
|
570
|
+
} else if (typeof RNDeviceInfo.getBuildNumber === 'function') {
|
|
571
|
+
try {
|
|
572
|
+
build = RNDeviceInfo.getBuildNumber();
|
|
573
|
+
} catch (e) {}
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
// 3. Try PlatformConstants / Platform.constants
|
|
579
|
+
const constants =
|
|
580
|
+
(Platform.constants as any) || NativeModules.PlatformConstants;
|
|
581
|
+
if (constants) {
|
|
582
|
+
if (
|
|
583
|
+
!version &&
|
|
584
|
+
constants.Version &&
|
|
585
|
+
typeof constants.Version === 'string' &&
|
|
586
|
+
constants.Version.includes('.')
|
|
587
|
+
) {
|
|
588
|
+
version = constants.Version;
|
|
589
|
+
}
|
|
590
|
+
if (!version && constants.reactNativeVersion) {
|
|
591
|
+
const rnv = constants.reactNativeVersion;
|
|
592
|
+
if (rnv.major !== undefined) {
|
|
593
|
+
version = `${rnv.major}.${rnv.minor}.${rnv.patch}`;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// 4. Try Android AppInfo
|
|
599
|
+
const AppInfo = NativeModules.AppInfo;
|
|
600
|
+
if (AppInfo) {
|
|
601
|
+
if (!version && typeof AppInfo.versionName === 'string') {
|
|
602
|
+
version = AppInfo.versionName;
|
|
603
|
+
}
|
|
604
|
+
if (!build && typeof AppInfo.versionCode === 'string') {
|
|
605
|
+
build = AppInfo.versionCode;
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
// Fallbacks
|
|
610
|
+
if (!version) version = '1.0.0';
|
|
611
|
+
if (!build) build = '1';
|
|
612
|
+
|
|
613
|
+
return {
|
|
614
|
+
version,
|
|
615
|
+
build,
|
|
616
|
+
formatted: `${version} (${build})`,
|
|
617
|
+
};
|
|
618
|
+
};
|
|
619
|
+
|
|
412
620
|
export const handleOpenExternalLink = (url: string): void => {
|
|
413
621
|
if (!url) return;
|
|
414
622
|
const openUrl = formatDisplayUrl(url);
|
|
@@ -18,8 +18,9 @@ export function matchNetworkLogQuery(
|
|
|
18
18
|
): boolean {
|
|
19
19
|
if (!searchQuery || searchQuery.trim().length === 0) return true;
|
|
20
20
|
|
|
21
|
+
// Split tokens by spaces or commas while respecting quotes
|
|
21
22
|
const rawTokens =
|
|
22
|
-
searchQuery.trim().match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g) || [];
|
|
23
|
+
searchQuery.trim().match(/(?:[^\s,"']+|"[^"]*"|'[^']*')+/g) || [];
|
|
23
24
|
|
|
24
25
|
if (rawTokens.length === 0) return true;
|
|
25
26
|
|
|
@@ -32,27 +33,38 @@ export function matchNetworkLogQuery(
|
|
|
32
33
|
const statusNum =
|
|
33
34
|
typeof log.status === 'number'
|
|
34
35
|
? log.status
|
|
35
|
-
:
|
|
36
|
-
|
|
36
|
+
: log.status != null
|
|
37
|
+
? parseInt(String(log.status), 10)
|
|
38
|
+
: null;
|
|
39
|
+
const statusStr = log.status != null ? String(log.status) : 'pending';
|
|
37
40
|
const durationNum = log.duration || 0;
|
|
38
41
|
const clientRaw = log.client || '';
|
|
42
|
+
const callerRaw = log.caller || '';
|
|
39
43
|
const reqRaw =
|
|
40
44
|
typeof log.request === 'string'
|
|
41
45
|
? log.request
|
|
42
|
-
:
|
|
46
|
+
: log.request != null
|
|
47
|
+
? JSON.stringify(log.request)
|
|
48
|
+
: '';
|
|
43
49
|
const resRaw =
|
|
44
50
|
typeof log.response === 'string'
|
|
45
51
|
? log.response
|
|
46
|
-
:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
const
|
|
52
|
+
: log.response != null
|
|
53
|
+
? JSON.stringify(log.response)
|
|
54
|
+
: '';
|
|
55
|
+
const reqHeadersRaw = log.requestHeaders
|
|
56
|
+
? JSON.stringify(log.requestHeaders)
|
|
57
|
+
: '';
|
|
58
|
+
const resHeadersRaw = log.responseHeaders
|
|
59
|
+
? JSON.stringify(log.responseHeaders)
|
|
60
|
+
: '';
|
|
61
|
+
const pathRaw = routePath || (log as any)?.routeInfo?.path || '';
|
|
50
62
|
|
|
51
63
|
// Construct search corpus based on active scope
|
|
52
64
|
const getScopedCorpus = (caseSens: boolean): string => {
|
|
53
65
|
let parts: string[] = [];
|
|
54
66
|
if (scope === 'url') {
|
|
55
|
-
parts = [methodRaw, urlRaw, pathRaw];
|
|
67
|
+
parts = [methodRaw, urlRaw, pathRaw, callerRaw];
|
|
56
68
|
} else if (scope === 'reqBody') {
|
|
57
69
|
parts = [reqRaw];
|
|
58
70
|
} else if (scope === 'resBody') {
|
|
@@ -65,6 +77,7 @@ export function matchNetworkLogQuery(
|
|
|
65
77
|
urlRaw,
|
|
66
78
|
statusStr,
|
|
67
79
|
pathRaw,
|
|
80
|
+
callerRaw,
|
|
68
81
|
clientRaw,
|
|
69
82
|
reqRaw,
|
|
70
83
|
resRaw,
|
|
@@ -81,6 +94,7 @@ export function matchNetworkLogQuery(
|
|
|
81
94
|
const methodStr = methodRaw.toLowerCase();
|
|
82
95
|
const urlStr = urlRaw.toLowerCase();
|
|
83
96
|
const clientStr = clientRaw.toLowerCase();
|
|
97
|
+
const callerStr = callerRaw.toLowerCase();
|
|
84
98
|
const reqStr = reqRaw.toLowerCase();
|
|
85
99
|
const resStr = resRaw.toLowerCase();
|
|
86
100
|
const reqHeadersStr = reqHeadersRaw.toLowerCase();
|
|
@@ -107,18 +121,20 @@ export function matchNetworkLogQuery(
|
|
|
107
121
|
// 2. status:<VAL> or s:<VAL>
|
|
108
122
|
if (lowerToken.startsWith('status:') || lowerToken.startsWith('s:')) {
|
|
109
123
|
const val = lowerToken.replace(/^(status:|s:)/, '').trim();
|
|
110
|
-
if (val
|
|
124
|
+
if (val === 'pending' || val === 'loading') {
|
|
125
|
+
if (log.status != null) return false;
|
|
126
|
+
} else if (val.startsWith('>=')) {
|
|
111
127
|
const threshold = parseInt(val.slice(2), 10);
|
|
112
|
-
if (isNaN(threshold) || statusNum < threshold) return false;
|
|
128
|
+
if (isNaN(threshold) || statusNum === null || statusNum < threshold) return false;
|
|
113
129
|
} else if (val.startsWith('>')) {
|
|
114
130
|
const threshold = parseInt(val.slice(1), 10);
|
|
115
|
-
if (isNaN(threshold) || statusNum <= threshold) return false;
|
|
131
|
+
if (isNaN(threshold) || statusNum === null || statusNum <= threshold) return false;
|
|
116
132
|
} else if (val.startsWith('<=')) {
|
|
117
133
|
const threshold = parseInt(val.slice(2), 10);
|
|
118
|
-
if (isNaN(threshold) || statusNum > threshold) return false;
|
|
134
|
+
if (isNaN(threshold) || statusNum === null || statusNum > threshold) return false;
|
|
119
135
|
} else if (val.startsWith('<')) {
|
|
120
136
|
const threshold = parseInt(val.slice(1), 10);
|
|
121
|
-
if (isNaN(threshold) || statusNum >= threshold) return false;
|
|
137
|
+
if (isNaN(threshold) || statusNum === null || statusNum >= threshold) return false;
|
|
122
138
|
} else if (val.endsWith('xx') || val.endsWith('x')) {
|
|
123
139
|
const prefix = val.replace(/x/g, '');
|
|
124
140
|
if (!statusStr.startsWith(prefix)) return false;
|
|
@@ -143,11 +159,13 @@ export function matchNetworkLogQuery(
|
|
|
143
159
|
flag === 'fail'
|
|
144
160
|
) {
|
|
145
161
|
const isErr =
|
|
146
|
-
log.status === 0 ||
|
|
162
|
+
log.status === 0 || (statusNum !== null && statusNum >= 400);
|
|
147
163
|
if (!isErr) return false;
|
|
148
164
|
} else if (flag === 'success' || flag === 'ok' || flag === '2xx') {
|
|
149
|
-
const isSuccess = statusNum >= 200 && statusNum < 300;
|
|
165
|
+
const isSuccess = statusNum !== null && statusNum >= 200 && statusNum < 300;
|
|
150
166
|
if (!isSuccess) return false;
|
|
167
|
+
} else if (flag === 'pending' || flag === 'loading') {
|
|
168
|
+
if (log.status != null) return false;
|
|
151
169
|
} else if (flag === 'slow') {
|
|
152
170
|
if (durationNum < 1000) return false;
|
|
153
171
|
} else if (flag === 'fast') {
|
|
@@ -169,6 +187,11 @@ export function matchNetworkLogQuery(
|
|
|
169
187
|
resHeadersStr.includes('application/json') ||
|
|
170
188
|
urlStr.includes('.json');
|
|
171
189
|
if (!isJson) return false;
|
|
190
|
+
} else if (flag === 'image') {
|
|
191
|
+
const isImg =
|
|
192
|
+
resHeadersStr.includes('image/') ||
|
|
193
|
+
/\.(png|jpe?g|gif|webp|svg)/i.test(urlStr);
|
|
194
|
+
if (!isImg) return false;
|
|
172
195
|
}
|
|
173
196
|
continue;
|
|
174
197
|
}
|
|
@@ -230,10 +253,20 @@ export function matchNetworkLogQuery(
|
|
|
230
253
|
continue;
|
|
231
254
|
}
|
|
232
255
|
|
|
233
|
-
// 7. path:<PATH> or p:<PATH>
|
|
234
|
-
if (
|
|
235
|
-
|
|
236
|
-
|
|
256
|
+
// 7. path:<PATH> or p:<PATH> or page:<PAGE>
|
|
257
|
+
if (
|
|
258
|
+
lowerToken.startsWith('path:') ||
|
|
259
|
+
lowerToken.startsWith('p:') ||
|
|
260
|
+
lowerToken.startsWith('page:')
|
|
261
|
+
) {
|
|
262
|
+
const targetPath = lowerToken
|
|
263
|
+
.replace(/^(path:|p:|page:)/, '')
|
|
264
|
+
.trim();
|
|
265
|
+
if (
|
|
266
|
+
!urlStr.includes(targetPath) &&
|
|
267
|
+
!pathStr.includes(targetPath) &&
|
|
268
|
+
!callerStr.includes(targetPath)
|
|
269
|
+
) {
|
|
237
270
|
return false;
|
|
238
271
|
}
|
|
239
272
|
continue;
|
|
@@ -274,6 +307,16 @@ export function matchNetworkLogQuery(
|
|
|
274
307
|
} else {
|
|
275
308
|
const queryTerm = isCaseSensitive ? token : lowerToken;
|
|
276
309
|
if (!targetCorpus.includes(queryTerm)) {
|
|
310
|
+
// Special case: if user typed "error" / "failed", check error status
|
|
311
|
+
if (
|
|
312
|
+
queryTerm === 'error' ||
|
|
313
|
+
queryTerm === 'failed' ||
|
|
314
|
+
queryTerm === 'fail'
|
|
315
|
+
) {
|
|
316
|
+
const isErr =
|
|
317
|
+
log.status === 0 || (statusNum !== null && statusNum >= 400);
|
|
318
|
+
if (isErr) continue;
|
|
319
|
+
}
|
|
277
320
|
return false;
|
|
278
321
|
}
|
|
279
322
|
}
|
package/src/i18n/index.ts
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import
|
|
2
|
+
import enLocale from './locales/en.json';
|
|
3
3
|
|
|
4
4
|
type TranslationParams = Record<string, any>;
|
|
5
5
|
|
|
6
|
+
const localeRegistry: Record<string, Record<string, any>> = {
|
|
7
|
+
en: enLocale,
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
let currentLanguage = 'en';
|
|
11
|
+
|
|
6
12
|
/**
|
|
7
13
|
* Lightweight nested lookup for translation keys (e.g. "network.headers")
|
|
8
14
|
*/
|
|
@@ -31,7 +37,12 @@ function interpolate(template: string, params?: TranslationParams): string {
|
|
|
31
37
|
* Standalone zero-dependency translation function
|
|
32
38
|
*/
|
|
33
39
|
export function t(key: string, optionsOrFallback?: TranslationParams | string): string {
|
|
34
|
-
const
|
|
40
|
+
const activeBundle = localeRegistry[currentLanguage] || localeRegistry.en;
|
|
41
|
+
let raw = lookupKey(activeBundle, key);
|
|
42
|
+
if (raw === undefined && currentLanguage !== 'en') {
|
|
43
|
+
raw = lookupKey(localeRegistry.en, key);
|
|
44
|
+
}
|
|
45
|
+
|
|
35
46
|
if (typeof raw === 'string') {
|
|
36
47
|
if (typeof optionsOrFallback === 'object' && optionsOrFallback !== null) {
|
|
37
48
|
return interpolate(raw, optionsOrFallback);
|
|
@@ -44,9 +55,33 @@ export function t(key: string, optionsOrFallback?: TranslationParams | string):
|
|
|
44
55
|
return key;
|
|
45
56
|
}
|
|
46
57
|
|
|
58
|
+
export function setLanguage(lang: string): void {
|
|
59
|
+
if (typeof lang === 'string' && lang.trim()) {
|
|
60
|
+
currentLanguage = lang.trim();
|
|
61
|
+
i18n.language = currentLanguage;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function addTranslations(lang: string, translations: Record<string, any>): void {
|
|
66
|
+
if (!lang || !translations || typeof translations !== 'object') return;
|
|
67
|
+
localeRegistry[lang] = {
|
|
68
|
+
...(localeRegistry[lang] || {}),
|
|
69
|
+
...translations,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function setTranslations(translations: Record<string, any>, lang: string = 'en'): void {
|
|
74
|
+
addTranslations(lang, translations);
|
|
75
|
+
}
|
|
76
|
+
|
|
47
77
|
export const i18n = {
|
|
48
78
|
t,
|
|
49
|
-
language:
|
|
79
|
+
language: currentLanguage,
|
|
80
|
+
changeLanguage: setLanguage,
|
|
81
|
+
addResourceBundle: (lng: string, _ns: string, resources: any) => addTranslations(lng, resources),
|
|
82
|
+
setLanguage,
|
|
83
|
+
addTranslations,
|
|
84
|
+
setTranslations,
|
|
50
85
|
};
|
|
51
86
|
|
|
52
87
|
/**
|