@dynatrace/react-native-plugin 2.343.1 → 2.347.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.
Files changed (60) hide show
  1. package/README.md +674 -656
  2. package/android/build.gradle +6 -2
  3. package/android/src/main/java/com/dynatrace/android/agent/DynatraceRNBridgeImpl.kt +24 -0
  4. package/files/plugin-runtime.gradle +17 -33
  5. package/files/plugin.gradle +1 -1
  6. package/instrumentation/BabelPluginDynatrace.js +1 -1
  7. package/instrumentation/libs/UserInteraction.js +20 -6
  8. package/instrumentation/libs/react-native/Lists.js +94 -0
  9. package/instrumentation/libs/react-native/index.js +4 -1
  10. package/instrumentation/libs/react-native.js +3 -0
  11. package/instrumentation/libs/react-navigation/ReactNavigation.js +14 -58
  12. package/instrumentation/libs/withOnPressMonitoring.js +3 -54
  13. package/internal.d.ts +2 -0
  14. package/internal.js +5 -1
  15. package/ios/DynatraceRNBridge.mm +37 -1
  16. package/lib/core/configuration/ConfigurationHandler.js +0 -21
  17. package/lib/core/logging/LogMessages.js +50 -0
  18. package/lib/dynatrace-reporter.js +1 -30
  19. package/lib/dynatrace-transformer.js +6 -34
  20. package/lib/next/configuration/INativeRuntimeConfiguration.js +0 -1
  21. package/lib/next/configuration/RuntimeConfigurationObserver.js +1 -6
  22. package/lib/next/events/spec/EventSpecContstants.js +1 -1
  23. package/lib/next/navigation/NavigationTracker.js +101 -0
  24. package/lib/next/navigation/useNavigationTracking.js +54 -0
  25. package/lib/next/triggers/TableReloadTracker.js +23 -0
  26. package/package.json +11 -21
  27. package/public.js +3 -1
  28. package/react-native-dynatrace.podspec +1 -1
  29. package/scripts/Android.js +1 -20
  30. package/scripts/Config.js +0 -4
  31. package/scripts/Deprecations.js +18 -0
  32. package/scripts/Install.js +13 -0
  33. package/scripts/PathsConstants.js +0 -4
  34. package/scripts/Uninstall.js +0 -15
  35. package/scripts/core/InstrumentCall.js +2 -3
  36. package/scripts/util/DeprecationReport.js +24 -0
  37. package/types.d.ts +212 -10
  38. package/instrumentation/DynatraceInstrumentation.js +0 -1
  39. package/instrumentation/libs/community/Picker.InstrInfo.js +0 -20
  40. package/instrumentation/libs/community/gesture-handler/Touchables.InstrInfo.js +0 -25
  41. package/instrumentation/libs/react-native/RefreshControl.InstrInfo.js +0 -12
  42. package/instrumentation/libs/react-native/Switch.InstrInfo.js +0 -12
  43. package/instrumentation/libs/react-native/Touchables.InstrInfo.js +0 -25
  44. package/instrumentation/model/Reference.js +0 -2
  45. package/instrumentation/parser/Babel.js +0 -60
  46. package/instrumentation/parser/ParserUtil.js +0 -11
  47. package/lib/features/ui-interaction/Config.js +0 -42
  48. package/lib/features/ui-interaction/IUserInteractionEvent.js +0 -16
  49. package/lib/features/ui-interaction/Plugin.Fragment.Test.js +0 -170
  50. package/lib/features/ui-interaction/Plugin.js +0 -289
  51. package/lib/features/ui-interaction/RootDetection.js +0 -51
  52. package/lib/features/ui-interaction/RootWrapper.js +0 -236
  53. package/lib/features/ui-interaction/Run.js +0 -38
  54. package/lib/features/ui-interaction/Runtime.js +0 -843
  55. package/lib/features/ui-interaction/TouchMetaResolver.js +0 -493
  56. package/lib/features/ui-interaction/Types.js +0 -14
  57. package/lib/metro/getSourceMapInfo.js +0 -26
  58. package/scripts/LineOffsetAnalyze.js +0 -25
  59. package/scripts/core/LineOffsetAnalyzeCall.js +0 -165
  60. package/scripts/util/SourceMapUtil.js +0 -68
@@ -29,7 +29,9 @@ buildscript {
29
29
  }
30
30
 
31
31
  apply plugin: 'com.android.library'
32
- apply plugin: 'org.jetbrains.kotlin.android'
32
+ if (!project.extensions.findByName('kotlin')) {
33
+ apply plugin: 'org.jetbrains.kotlin.android'
34
+ }
33
35
 
34
36
  if (isNewArchitectureEnabled()) {
35
37
  apply plugin: 'com.facebook.react'
@@ -68,8 +70,10 @@ android {
68
70
  main {
69
71
  if (isNewArchitectureEnabled()) {
70
72
  java.srcDirs += ['src/new']
73
+ kotlin.srcDirs += ['src/new']
71
74
  } else {
72
75
  java.srcDirs += ['src/old']
76
+ kotlin.srcDirs += ['src/old']
73
77
  }
74
78
  }
75
79
  }
@@ -81,7 +85,7 @@ repositories {
81
85
  }
82
86
 
83
87
  dependencies {
84
- implementation 'com.dynatrace.agent:agent-android:8.343.1.1038'
88
+ implementation 'com.dynatrace.agent:agent-android:8.347.1.1003'
85
89
  implementation "com.facebook.react:react-native:${safeExtGet('reactNative', '+')}"
86
90
  }
87
91
 
@@ -1,6 +1,9 @@
1
1
  package com.dynatrace.android.agent
2
2
 
3
3
  import android.location.Location
4
+ import android.os.Handler
5
+ import android.os.Looper
6
+ import android.view.Choreographer
4
7
  import com.dynatrace.android.agent.conf.DataCollectionLevel
5
8
  import com.dynatrace.android.agent.conf.DynatraceConfigurationBuilder
6
9
  import com.dynatrace.android.agent.conf.UserPrivacyOptions
@@ -46,6 +49,7 @@ class DynatraceRNBridgeImpl(
46
49
  private var lastConfiguration: MutableMap<String, Any>? = null
47
50
  private var hasInternalListener: Boolean = false
48
51
  private var listenersCount: Int = 0
52
+ private val navGeneration = java.util.concurrent.atomic.AtomicInteger(0)
49
53
 
50
54
  fun getConstants(): Map<String, Any> {
51
55
  return constants;
@@ -472,8 +476,28 @@ class DynatraceRNBridgeImpl(
472
476
  }
473
477
  }
474
478
 
479
+ // NOTE: This callback is observational only — it measures the first rendered frame for
480
+ // diagnostic tooling (LOAD TIME display). It does not defer stopView(); deferring the
481
+ // view-end to the rendered frame to fix TTID under-reporting (DEM-32277) is a separate task.
475
482
  fun startViewInternal(fields: ReadableMap) {
483
+ val imNanos = System.nanoTime()
484
+ val gen = navGeneration.incrementAndGet()
476
485
  HybridBridge.startView(JSONObject(DynatraceUtils.toHashMap(fields)))
486
+ Handler(Looper.getMainLooper()).post {
487
+ Choreographer.getInstance().postFrameCallback { frameTimeNanos ->
488
+ // Discard stale callbacks superseded by a newer navigation.
489
+ if (navGeneration.get() != gen) return@postFrameCallback
490
+ val frameEpochMs = System.currentTimeMillis()
491
+ val deltaMs = (frameTimeNanos - imNanos) / 1_000_000.0
492
+ val params = Arguments.createMap().apply {
493
+ putDouble("frameEndMs", frameEpochMs.toDouble())
494
+ putDouble("deltaMs", deltaMs)
495
+ }
496
+ reactApplicationContext
497
+ .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter::class.java)
498
+ .emit("DTNavigationFrame", params)
499
+ }
500
+ }
477
501
  }
478
502
 
479
503
  fun stopViewInternal() {
@@ -1,33 +1,17 @@
1
- import org.gradle.process.ExecOperations
2
- import javax.inject.Inject
3
-
4
- abstract class RunLineOffsetTask extends DefaultTask {
5
- @Internal
6
- abstract DirectoryProperty getWorkingDirectory()
7
-
8
- @Inject
9
- abstract ExecOperations getExecOperations()
10
-
11
- @TaskAction
12
- void run() {
13
- execOperations.exec {
14
- workingDir workingDirectory.get().asFile
15
- if (System.getProperty('os.name').toLowerCase().contains('windows')) {
16
- commandLine 'cmd', '/c', 'npx', 'lineOffsetDynatrace'
17
- } else {
18
- commandLine 'npx', 'lineOffsetDynatrace'
19
- }
20
- }
21
- }
22
- }
23
-
24
- android.applicationVariants.all { variant ->
25
- if (variant.buildType.name == "release") {
26
- def lineOffsetTask = tasks.register("runLineOffset${variant.name.capitalize()}", RunLineOffsetTask) {
27
- workingDirectory = layout.projectDirectory
28
- }
29
- variant.mergeAssetsProvider.configure { task ->
30
- task.dependsOn(lineOffsetTask)
31
- }
32
- }
33
- }
1
+ // Intentionally left empty. DO NOT DELETE THIS FILE.
2
+ //
3
+ // Apps instrumented with an older version of this plugin have the following
4
+ // line hard-coded in their android/app/build.gradle:
5
+ //
6
+ // apply from: "../../node_modules/@dynatrace/react-native-plugin/files/plugin-runtime.gradle"
7
+ //
8
+ // That line lives in the customer's own build.gradle, so we cannot reliably
9
+ // remove it on upgrade. If this file were missing, the `apply from:` above
10
+ // would fail the Gradle build for every app that still has that line.
11
+ //
12
+ // Previously this script registered a release-build Gradle task that ran
13
+ // `npx lineOffsetDynatrace` for line-offset analysis. That is no longer needed:
14
+ // auto-instrumentation moved to a Babel plugin and capturing moved to native,
15
+ // so the script is now a no-op kept purely for backward compatibility.
16
+ //
17
+ // New installs no longer add the `apply from:` line at all.
@@ -1,4 +1,4 @@
1
1
  // TEMPLATE: plugin-gradle.template
2
2
  dependencies {
3
- classpath 'com.dynatrace.tools.android:gradle-plugin:8.343.1.1038'
3
+ classpath 'com.dynatrace.tools.android:gradle-plugin:8.347.1.1003'
4
4
  }
@@ -1 +1 @@
1
- var _templateObject,_templateObject2,_templateObject3,_templateObject4,_templateObject5,_templateObject6,_interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault"),_taggedTemplateLiteral2=_interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral"));function _createForOfIteratorHelper(e,t){var n,r,a,i,o="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(o)return a=!(r=!0),{s:function(){o=o.call(e)},n:function(){var e=o.next();return r=e.done,e},e:function(e){a=!0,n=e},f:function(){try{r||null==o.return||o.return()}finally{if(a)throw n}}};if(Array.isArray(e)||(o=_unsupportedIterableToArray(e))||t&&e&&"number"==typeof e.length)return o&&(e=o),i=0,{s:t=function(){},n:function(){return i>=e.length?{done:!0}:{done:!1,value:e[i++]}},e:function(e){throw e},f:t};throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _unsupportedIterableToArray(e,t){var n;if(e)return"string"==typeof e?_arrayLikeToArray(e,t):"Map"===(n="Object"===(n={}.toString.call(e).slice(8,-1))&&e.constructor?e.constructor.name:n)||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?_arrayLikeToArray(e,t):void 0}function _arrayLikeToArray(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n<t;n++)r[n]=e[n];return r}Object.defineProperty(exports,"__esModule",{value:!0});var reactOptions,fspath=require("path"),fs=require("fs"),core_1=require("@babel/core"),generator_1=require("@babel/generator"),PathsConstants_1=require("../scripts/PathsConstants"),Config_1=require("../scripts/Config"),GetValuesFromPackage_1=require("../lib/core/util/GetValuesFromPackage"),Types_1=require("./model/Types"),INSTRUMENTATION_LIBS="@dynatrace/react-native-plugin/instrumentation/libs",COMPONENTS_EXCLUDED_FROM_UIA=new Set(["Fragment","React.Fragment"]),hasJSX=function(e){var t=!1;return e.traverse({"JSXElement|JSXFragment":function(){t=!0}}),t},instrumentUserInteraction=function(e){e.traverse({"FunctionDeclaration|ObjectMethod":function(e){var e=e.node,t=core_1.types.isFunctionDeclaration(e)?e.id:e.key;core_1.types.isIdentifier(t,{name:"registerComponent"})&&(t="".concat(INSTRUMENTATION_LIBS,"/UserInteraction"),e.body.body.unshift(core_1.template.statement('componentProvider = require("'.concat(t,'").wrapProvider(componentProvider);'))()))}})},instrumentAppRegistry=function(e){e.traverse({"FunctionDeclaration|ObjectMethod":function(e){var e=e.node,t=core_1.types.isFunctionDeclaration(e)?e.id:e.key;core_1.types.isIdentifier(t,{name:"runApplication"})&&e.body.body.unshift(core_1.template.statement(_templateObject=_templateObject||(0,_taggedTemplateLiteral2.default)(['require("@dynatrace/react-native-plugin").ApplicationHandler.startup();']))())}})},instrumentExceptionsManager=function(e){var t,n=null!=(t=null==(t=null==reactOptions?void 0:reactOptions.errorHandler)?void 0:t.reportFatalErrorAsCrash)&&t,r=(null==reactOptions?void 0:reactOptions.autoStart)&&(null==(t=null==reactOptions?void 0:reactOptions.errorHandler)?void 0:t.enabled);e.traverse({FunctionDeclaration:function(e){var t;core_1.types.isIdentifier(e.node.id,{name:"handleException"})&&(t=core_1.template.statement(_templateObject2=_templateObject2||(0,_taggedTemplateLiteral2.default)(['\n setTimeout(() => BODY, require("@dynatrace/react-native-plugin/lib/core/ErrorHandler")\n .reportErrorToDynatrace(e, isFatal, CRASH, AUTO));\n ']))({BODY:core_1.types.cloneNode(e.node.body),CRASH:core_1.types.booleanLiteral(n),AUTO:core_1.types.booleanLiteral(!!r)}),e.node.body.body=[t])}})},instrumentCssInterop=function(e){e.traverse({CallExpression:function(e){core_1.types.isIdentifier(e.node.callee,{name:"require"})&&(e=e.node.arguments[0],core_1.types.isStringLiteral(e))&&("react/jsx-runtime"===e.value?e.value="@dynatrace/react-native-plugin/jsx-runtime":"react/jsx-dev-runtime"===e.value&&(e.value="@dynatrace/react-native-plugin/jsx-dev-runtime"))}})},instrumentNavigation=function(e){e.traverse({VariableDeclarator:function(e){var t;core_1.types.isIdentifier(e.node.id,{name:"getRootState"})&&(t=core_1.template.statement(_templateObject3=_templateObject3||(0,_taggedTemplateLiteral2.default)(["\n require(PATH).monitorNavigation(getRootState);\n "]))({PATH:core_1.types.stringLiteral("".concat(INSTRUMENTATION_LIBS,"/react-navigation/ReactNavigation"))}),e.parentPath.insertAfter(t))}})},instrumentReactCreateElement=function(e){var t=core_1.template.statement(_templateObject4=_templateObject4||(0,_taggedTemplateLiteral2.default)(["\n require(PATH).instrumentCreateElement(module.exports);\n "]))({PATH:core_1.types.stringLiteral("@dynatrace/react-native-plugin/instrumentation/jsx/ElementHelper")});e.pushContainer("body",t)},instrumentComponents=function(e,n){e.traverse({FunctionDeclaration:function(e){var t;hasJSX(e)&&(t=e.node,core_1.types.isIdentifier(t.id))&&null!=(e=e.getStatementParent())&&e.insertAfter(n(t.id.name,Types_1.Types.FunctionalComponent))},ClassDeclaration:function(e){var t;hasJSX(e)&&(t=e.node,core_1.types.isIdentifier(t.id))&&null!=(e=e.getStatementParent())&&e.insertAfter(n(t.id.name,Types_1.Types.ClassComponent))},"FunctionExpression|ArrowFunctionExpression":function(e){var t;hasJSX(e)&&(t=e.parent,void 0!==(t=core_1.types.isVariableDeclarator(t)&&core_1.types.isIdentifier(t.id)?t.id.name:core_1.types.isAssignmentExpression(t)&&core_1.types.isIdentifier(t.left)?t.left.name:void 0))&&null!=(e=e.getStatementParent())&&e.insertAfter(n(t,Types_1.Types.FunctionalComponent))}})},instrumentLifecycle=function(e){instrumentComponents(e,function(e,t){return core_1.template.statement(_templateObject5=_templateObject5||(0,_taggedTemplateLiteral2.default)(["NAME._dtInfo = { type: TYPE, name: 'NAME_STR' }"]))({NAME:core_1.types.identifier(e),TYPE:core_1.types.numericLiteral(t),NAME_STR:core_1.types.stringLiteral(e)})})},instrumentComponentNames=function(e){instrumentComponents(e,function(e){return core_1.template.statement(_templateObject6=_templateObject6||(0,_taggedTemplateLiteral2.default)(["NAME.dtName = 'NAME_STR'"]))({NAME:core_1.types.identifier(e),NAME_STR:core_1.types.stringLiteral(e)})})},instrumentInput=function(e){var u=new Map([["react-native",{proxy:"".concat(INSTRUMENTATION_LIBS,"/react-native/"),components:new Set(["TouchableHighlight","TouchableNativeFeedback","TouchableOpacity","TouchableWithoutFeedback","Button","RefreshControl","Text","Pressable","Switch"])}],["react-native-gesture-handler",{proxy:"".concat(INSTRUMENTATION_LIBS,"/community/gesture-handler/"),components:new Set(["TouchableHighlight","TouchableNativeFeedback","TouchableOpacity","TouchableWithoutFeedback","RectButton","BorderlessButton","BaseButton"])}],["@react-native-picker/picker",{proxy:"".concat(INSTRUMENTATION_LIBS,"/community/Picker"),components:new Set(["Picker","PickerIOS"])}]]);e.traverse({ImportDeclaration:function(e){if(void 0===e.node.processed){var t=e.node.source;if(u.has(t.value)){var r=u.get(t.value),n=e.node.specifiers,a=[],i=[];if(n.forEach(function(e,t){var n;core_1.types.isImportSpecifier(e)&&(n=core_1.types.isIdentifier(e.imported)?e.imported.name:e.imported.value,r.components.has(n)||(a.push(e),i.push(t)))}),a.length!==n.length){var o,s=_createForOfIteratorHelper([].concat(i).reverse());try{for(s.s();!(o=s.n()).done;){var c=o.value;n.splice(c,1)}}catch(e){s.e(e)}finally{s.f()}0<a.length&&((t=core_1.types.importDeclaration(a,core_1.types.stringLiteral(t.value))).processed=!0,e.insertBefore(t)),e.node.source=core_1.types.stringLiteral(r.proxy),e.scope.crawl()}}}},CallExpression:function(e){core_1.types.isIdentifier(e.node.callee,{name:"require"})&&(e=e.node.arguments[0],core_1.types.isStringLiteral(e))&&u.has(e.value)&&(e.value=u.get(e.value).proxy)}})},instrumentJsxNames=function(e){e.traverse({JSXOpeningElement:function(e){var t=e.node.name,t=core_1.types.isJSXIdentifier(t)?t.name:core_1.types.isJSXMemberExpression(t)?(0,generator_1.default)(t).code:void 0;t&&!COMPONENTS_EXCLUDED_FROM_UIA.has(t)&&e.node.attributes.unshift(core_1.types.jsxAttribute(core_1.types.jsxIdentifier("dtName"),core_1.types.stringLiteral(t)))}})},instrumentConfigurationPreset=function(e){var t,n=(0,GetValuesFromPackage_1.getHostAppBundleInfo)(PathsConstants_1.default.getPackageJsonFile()),r={getLifecycleUpdate:reactOptions.lifecycle.includeUpdate,getLogLevel:reactOptions.debug?0:1,getBundleName:null!=(t=reactOptions.bundleName)?t:null==n?void 0:n.name,getBundleVersion:null!=(t=reactOptions.bundleVersion)?t:null==n?void 0:n.version,getActionNamePrivacy:reactOptions.input.actionNamePrivacy,getActionNamePreference:reactOptions.input.actionNamePreference,getActionNameAlgorithm:reactOptions.input.actionNameAlgorithm,isErrorHandlerEnabled:reactOptions.errorHandler.enabled,isReportFatalErrorAsCrash:reactOptions.errorHandler.reportFatalErrorAsCrash,isAutoStartupEnabled:reactOptions.autoStart};e.traverse({ClassMethod:function(e){var t;core_1.types.isIdentifier(e.node.key)&&void 0!==(t=r[e.node.key.name])&&(e=e.node.body.body[0],core_1.types.isReturnStatement(e))&&(e.argument=core_1.types.valueToNode(t))}})},createFilenameMatcher=function(r){return{isModule:function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.some(function(e){return r.includes(fspath.join("node_modules",e)+fspath.sep)})},isFile:function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.some(function(e){return r.endsWith(e)})}}},captureOriginalCode=function(e){return!0!==reactOptions.debugBabelPlugin?"":(0,generator_1.default)(e.node).code},isConfigurationPresetTarget=function(e){return e.isModule("@dynatrace")&&e.isFile("ConfigurationPreset.js")},isAppRegistryTarget=function(e){return e.isModule("react-native")&&e.isFile("AppRegistry.js","AppRegistryImpl.js")},isExceptionsManagerTarget=function(e){return e.isModule("react-native")&&e.isFile("ExceptionsManager.js")},isCssInteropTarget=function(e){return e.isModule("react-native-css-interop")&&e.isFile("jsx-runtime.js","jsx-dev-runtime.js")},isNavigationTarget=function(e){return reactOptions.navigation.enabled&&e.isModule("@react-navigation")&&e.isFile("BaseNavigationContainer.js","BaseNavigationContainer.tsx")},isReactIndexTarget=function(e){return e.isModule("react")&&e.isFile("index.js")},shouldInstrumentLifecycleForFile=function(e,t,n){var r,a,n=n.isModule("react-native")&&n.isFile("renderApplication.js");return(null==(a=null==(r=reactOptions.lifecycle)?void 0:r.instrument)?void 0:a.call(r,t))&&(!t.includes("node_modules")||n)&&hasJSX(e)},shouldInstrumentInputForFile=function(e,t){var n,r,t=t.isModule("@react-navigation","react-native-drawer-layout");return(null==(r=null==(n=reactOptions.input)?void 0:n.instrument)?void 0:r.call(n,e))&&(!e.includes("node_modules")||t)},shouldInstrumentUserInteractionNames=function(e){return reactOptions.userInteraction&&!e.includes("node_modules")},instrumentByModuleAndFile=function(e,t,n){isConfigurationPresetTarget(n)&&instrumentConfigurationPreset(e),isAppRegistryTarget(n)&&(reactOptions.autoStart&&instrumentAppRegistry(e),reactOptions.userInteraction)&&instrumentUserInteraction(e),isExceptionsManagerTarget(n)&&instrumentExceptionsManager(e),isCssInteropTarget(n)&&instrumentCssInterop(e),isNavigationTarget(n)&&instrumentNavigation(e),isReactIndexTarget(n)&&instrumentReactCreateElement(e),shouldInstrumentLifecycleForFile(e,t,n)&&instrumentLifecycle(e),shouldInstrumentInputForFile(t,n)&&instrumentInput(e),shouldInstrumentUserInteractionNames(t)&&(instrumentJsxNames(e),instrumentComponentNames(e))},writeDebugOutputIfChanged=function(e,t,n,r){!0===reactOptions.debugBabelPlugin&&(e=(0,generator_1.default)(e.node).code)!==r&&(r=fspath.join(PathsConstants_1.default.getBuildPath(),fspath.relative(PathsConstants_1.default.getApplicationPath(),n)+".dtx"),fs.mkdirSync(fspath.dirname(r),{recursive:!0}),fs.writeFileSync(r,e),t.set("fileDidChange",!0))};exports.default=function(){return{visitor:{Program:function(e,t){reactOptions=(0,Config_1.readConfigDefault)().react;var n,r,a=t.filename;void 0!==a&&(n=createFilenameMatcher(a),r=captureOriginalCode(e),instrumentByModuleAndFile(e,a,n),writeDebugOutputIfChanged(e,t,a,r))}},post:function(e){var t;!0===reactOptions.debugBabelPlugin&&!0===this.get("fileDidChange")&&(t=(0,generator_1.default)(e.ast).code,e=fspath.join(PathsConstants_1.default.getBuildPath(),fspath.relative(PathsConstants_1.default.getApplicationPath(),e.opts.filename)+".dtx.downstream"),fs.mkdirSync(fspath.dirname(e),{recursive:!0}),fs.writeFileSync(e,t))}}};
1
+ var _templateObject,_templateObject2,_templateObject3,_templateObject4,_templateObject5,_templateObject6,_interopRequireDefault=require("@babel/runtime/helpers/interopRequireDefault"),_taggedTemplateLiteral2=_interopRequireDefault(require("@babel/runtime/helpers/taggedTemplateLiteral"));function _createForOfIteratorHelper(e,t){var n,r,a,i,o="undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(o)return a=!(r=!0),{s:function(){o=o.call(e)},n:function(){var e=o.next();return r=e.done,e},e:function(e){a=!0,n=e},f:function(){try{r||null==o.return||o.return()}finally{if(a)throw n}}};if(Array.isArray(e)||(o=_unsupportedIterableToArray(e))||t&&e&&"number"==typeof e.length)return o&&(e=o),i=0,{s:t=function(){},n:function(){return i>=e.length?{done:!0}:{done:!1,value:e[i++]}},e:function(e){throw e},f:t};throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _unsupportedIterableToArray(e,t){var n;if(e)return"string"==typeof e?_arrayLikeToArray(e,t):"Map"===(n="Object"===(n={}.toString.call(e).slice(8,-1))&&e.constructor?e.constructor.name:n)||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?_arrayLikeToArray(e,t):void 0}function _arrayLikeToArray(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=Array(t);n<t;n++)r[n]=e[n];return r}Object.defineProperty(exports,"__esModule",{value:!0});var reactOptions,fspath=require("path"),fs=require("fs"),core_1=require("@babel/core"),generator_1=require("@babel/generator"),PathsConstants_1=require("../scripts/PathsConstants"),Config_1=require("../scripts/Config"),GetValuesFromPackage_1=require("../lib/core/util/GetValuesFromPackage"),Types_1=require("./model/Types"),INSTRUMENTATION_LIBS="@dynatrace/react-native-plugin/instrumentation/libs",COMPONENTS_EXCLUDED_FROM_UIA=new Set(["Fragment","React.Fragment"]),hasJSX=function(e){var t=!1;return e.traverse({"JSXElement|JSXFragment":function(){t=!0}}),t},instrumentUserInteraction=function(e){e.traverse({"FunctionDeclaration|ObjectMethod":function(e){var e=e.node,t=core_1.types.isFunctionDeclaration(e)?e.id:e.key;core_1.types.isIdentifier(t,{name:"registerComponent"})&&(t="".concat(INSTRUMENTATION_LIBS,"/UserInteraction"),e.body.body.unshift(core_1.template.statement('componentProvider = require("'.concat(t,'").wrapProvider(componentProvider);'))()))}})},instrumentAppRegistry=function(e){e.traverse({"FunctionDeclaration|ObjectMethod":function(e){var e=e.node,t=core_1.types.isFunctionDeclaration(e)?e.id:e.key;core_1.types.isIdentifier(t,{name:"runApplication"})&&e.body.body.unshift(core_1.template.statement(_templateObject=_templateObject||(0,_taggedTemplateLiteral2.default)(['require("@dynatrace/react-native-plugin").ApplicationHandler.startup();']))())}})},instrumentExceptionsManager=function(e){var t,n=null!=(t=null==(t=null==reactOptions?void 0:reactOptions.errorHandler)?void 0:t.reportFatalErrorAsCrash)&&t,r=(null==reactOptions?void 0:reactOptions.autoStart)&&(null==(t=null==reactOptions?void 0:reactOptions.errorHandler)?void 0:t.enabled);e.traverse({FunctionDeclaration:function(e){var t;core_1.types.isIdentifier(e.node.id,{name:"handleException"})&&(t=core_1.template.statement(_templateObject2=_templateObject2||(0,_taggedTemplateLiteral2.default)(['\n setTimeout(() => BODY, require("@dynatrace/react-native-plugin/lib/core/ErrorHandler")\n .reportErrorToDynatrace(e, isFatal, CRASH, AUTO));\n ']))({BODY:core_1.types.cloneNode(e.node.body),CRASH:core_1.types.booleanLiteral(n),AUTO:core_1.types.booleanLiteral(!!r)}),e.node.body.body=[t])}})},instrumentCssInterop=function(e){e.traverse({CallExpression:function(e){core_1.types.isIdentifier(e.node.callee,{name:"require"})&&(e=e.node.arguments[0],core_1.types.isStringLiteral(e))&&("react/jsx-runtime"===e.value?e.value="@dynatrace/react-native-plugin/jsx-runtime":"react/jsx-dev-runtime"===e.value&&(e.value="@dynatrace/react-native-plugin/jsx-dev-runtime"))}})},instrumentNavigation=function(e){e.traverse({VariableDeclarator:function(e){var t;core_1.types.isIdentifier(e.node.id,{name:"getRootState"})&&(t=core_1.template.statement(_templateObject3=_templateObject3||(0,_taggedTemplateLiteral2.default)(["\n require(PATH).useNavigationMonitor(getRootState);\n "]))({PATH:core_1.types.stringLiteral("".concat(INSTRUMENTATION_LIBS,"/react-navigation/ReactNavigation"))}),e.parentPath.insertAfter(t))}})},instrumentReactCreateElement=function(e){var t=core_1.template.statement(_templateObject4=_templateObject4||(0,_taggedTemplateLiteral2.default)(["\n require(PATH).instrumentCreateElement(module.exports);\n "]))({PATH:core_1.types.stringLiteral("@dynatrace/react-native-plugin/instrumentation/jsx/ElementHelper")});e.pushContainer("body",t)},instrumentComponents=function(e,n){e.traverse({FunctionDeclaration:function(e){var t;hasJSX(e)&&(t=e.node,core_1.types.isIdentifier(t.id))&&null!=(e=e.getStatementParent())&&e.insertAfter(n(t.id.name,Types_1.Types.FunctionalComponent))},ClassDeclaration:function(e){var t;hasJSX(e)&&(t=e.node,core_1.types.isIdentifier(t.id))&&null!=(e=e.getStatementParent())&&e.insertAfter(n(t.id.name,Types_1.Types.ClassComponent))},"FunctionExpression|ArrowFunctionExpression":function(e){var t;hasJSX(e)&&(t=e.parent,void 0!==(t=core_1.types.isVariableDeclarator(t)&&core_1.types.isIdentifier(t.id)?t.id.name:core_1.types.isAssignmentExpression(t)&&core_1.types.isIdentifier(t.left)?t.left.name:void 0))&&null!=(e=e.getStatementParent())&&e.insertAfter(n(t,Types_1.Types.FunctionalComponent))}})},instrumentLifecycle=function(e){instrumentComponents(e,function(e,t){return core_1.template.statement(_templateObject5=_templateObject5||(0,_taggedTemplateLiteral2.default)(["NAME._dtInfo = { type: TYPE, name: 'NAME_STR' }"]))({NAME:core_1.types.identifier(e),TYPE:core_1.types.numericLiteral(t),NAME_STR:core_1.types.stringLiteral(e)})})},instrumentComponentNames=function(e){instrumentComponents(e,function(e){return core_1.template.statement(_templateObject6=_templateObject6||(0,_taggedTemplateLiteral2.default)(["NAME.dtName = 'NAME_STR'"]))({NAME:core_1.types.identifier(e),NAME_STR:core_1.types.stringLiteral(e)})})},instrumentInput=function(e){var u=new Map([["react-native",{proxy:"".concat(INSTRUMENTATION_LIBS,"/react-native/"),components:new Set(["TouchableHighlight","TouchableNativeFeedback","TouchableOpacity","TouchableWithoutFeedback","Button","RefreshControl","Text","Pressable","Switch","FlatList","SectionList"])}],["react-native-gesture-handler",{proxy:"".concat(INSTRUMENTATION_LIBS,"/community/gesture-handler/"),components:new Set(["TouchableHighlight","TouchableNativeFeedback","TouchableOpacity","TouchableWithoutFeedback","RectButton","BorderlessButton","BaseButton"])}],["@react-native-picker/picker",{proxy:"".concat(INSTRUMENTATION_LIBS,"/community/Picker"),components:new Set(["Picker","PickerIOS"])}]]);e.traverse({ImportDeclaration:function(e){if(void 0===e.node.processed){var t=e.node.source;if(u.has(t.value)){var r=u.get(t.value),n=e.node.specifiers,a=[],i=[];if(n.forEach(function(e,t){var n;core_1.types.isImportSpecifier(e)&&(n=core_1.types.isIdentifier(e.imported)?e.imported.name:e.imported.value,r.components.has(n)||(a.push(e),i.push(t)))}),a.length!==n.length){var o,s=_createForOfIteratorHelper([].concat(i).reverse());try{for(s.s();!(o=s.n()).done;){var c=o.value;n.splice(c,1)}}catch(e){s.e(e)}finally{s.f()}0<a.length&&((t=core_1.types.importDeclaration(a,core_1.types.stringLiteral(t.value))).processed=!0,e.insertBefore(t)),e.node.source=core_1.types.stringLiteral(r.proxy),e.scope.crawl()}}}},CallExpression:function(e){core_1.types.isIdentifier(e.node.callee,{name:"require"})&&(e=e.node.arguments[0],core_1.types.isStringLiteral(e))&&u.has(e.value)&&(e.value=u.get(e.value).proxy)}})},instrumentJsxNames=function(e){e.traverse({JSXOpeningElement:function(e){var t=e.node.name,t=core_1.types.isJSXIdentifier(t)?t.name:core_1.types.isJSXMemberExpression(t)?(0,generator_1.default)(t).code:void 0;t&&!COMPONENTS_EXCLUDED_FROM_UIA.has(t)&&e.node.attributes.unshift(core_1.types.jsxAttribute(core_1.types.jsxIdentifier("dtName"),core_1.types.stringLiteral(t)))}})},instrumentConfigurationPreset=function(e){var t,n=(0,GetValuesFromPackage_1.getHostAppBundleInfo)(PathsConstants_1.default.getPackageJsonFile()),r={getLifecycleUpdate:reactOptions.lifecycle.includeUpdate,getLogLevel:reactOptions.debug?0:1,getBundleName:null!=(t=reactOptions.bundleName)?t:null==n?void 0:n.name,getBundleVersion:null!=(t=reactOptions.bundleVersion)?t:null==n?void 0:n.version,getActionNamePrivacy:reactOptions.input.actionNamePrivacy,getActionNamePreference:reactOptions.input.actionNamePreference,getActionNameAlgorithm:reactOptions.input.actionNameAlgorithm,isErrorHandlerEnabled:reactOptions.errorHandler.enabled,isReportFatalErrorAsCrash:reactOptions.errorHandler.reportFatalErrorAsCrash,isAutoStartupEnabled:reactOptions.autoStart};e.traverse({ClassMethod:function(e){var t;core_1.types.isIdentifier(e.node.key)&&void 0!==(t=r[e.node.key.name])&&(e=e.node.body.body[0],core_1.types.isReturnStatement(e))&&(e.argument=core_1.types.valueToNode(t))}})},createFilenameMatcher=function(r){return{isModule:function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.some(function(e){return r.includes(fspath.join("node_modules",e)+fspath.sep)})},isFile:function(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.some(function(e){return r.endsWith(e)})}}},captureOriginalCode=function(e){return!0!==reactOptions.debugBabelPlugin?"":(0,generator_1.default)(e.node).code},isConfigurationPresetTarget=function(e){return e.isModule("@dynatrace")&&e.isFile("ConfigurationPreset.js")},isAppRegistryTarget=function(e){return e.isModule("react-native")&&e.isFile("AppRegistry.js","AppRegistryImpl.js")},isExceptionsManagerTarget=function(e){return e.isModule("react-native")&&e.isFile("ExceptionsManager.js")},isCssInteropTarget=function(e){return e.isModule("react-native-css-interop")&&e.isFile("jsx-runtime.js","jsx-dev-runtime.js")},isNavigationTarget=function(e){return reactOptions.navigation.enabled&&e.isModule("@react-navigation")&&e.isFile("BaseNavigationContainer.js","BaseNavigationContainer.tsx")},isReactIndexTarget=function(e){return e.isModule("react")&&e.isFile("index.js")},shouldInstrumentLifecycleForFile=function(e,t,n){var r,a,n=n.isModule("react-native")&&n.isFile("renderApplication.js");return(null==(a=null==(r=reactOptions.lifecycle)?void 0:r.instrument)?void 0:a.call(r,t))&&(!t.includes("node_modules")||n)&&hasJSX(e)},shouldInstrumentInputForFile=function(e,t){var n,r,t=t.isModule("@react-navigation","react-native-drawer-layout");return(null==(r=null==(n=reactOptions.input)?void 0:n.instrument)?void 0:r.call(n,e))&&(!e.includes("node_modules")||t)},shouldInstrumentUserInteractionNames=function(e){return reactOptions.userInteraction&&!e.includes("node_modules")},instrumentByModuleAndFile=function(e,t,n){isConfigurationPresetTarget(n)&&instrumentConfigurationPreset(e),isAppRegistryTarget(n)&&(reactOptions.autoStart&&instrumentAppRegistry(e),reactOptions.userInteraction)&&instrumentUserInteraction(e),isExceptionsManagerTarget(n)&&instrumentExceptionsManager(e),isCssInteropTarget(n)&&instrumentCssInterop(e),isNavigationTarget(n)&&instrumentNavigation(e),isReactIndexTarget(n)&&instrumentReactCreateElement(e),shouldInstrumentLifecycleForFile(e,t,n)&&instrumentLifecycle(e),shouldInstrumentInputForFile(t,n)&&instrumentInput(e),shouldInstrumentUserInteractionNames(t)&&(instrumentJsxNames(e),instrumentComponentNames(e))},writeDebugOutputIfChanged=function(e,t,n,r){!0===reactOptions.debugBabelPlugin&&(e=(0,generator_1.default)(e.node).code)!==r&&(r=fspath.join(PathsConstants_1.default.getBuildPath(),fspath.relative(PathsConstants_1.default.getApplicationPath(),n)+".dtx"),fs.mkdirSync(fspath.dirname(r),{recursive:!0}),fs.writeFileSync(r,e),t.set("fileDidChange",!0))};exports.default=function(){return{visitor:{Program:function(e,t){reactOptions=(0,Config_1.readConfigDefault)().react;var n,r,a=t.filename;void 0!==a&&(n=createFilenameMatcher(a),r=captureOriginalCode(e),instrumentByModuleAndFile(e,a,n),writeDebugOutputIfChanged(e,t,a,r))}},post:function(e){var t;!0===reactOptions.debugBabelPlugin&&!0===this.get("fileDidChange")&&(t=(0,generator_1.default)(e.ast).code,e=fspath.join(PathsConstants_1.default.getBuildPath(),fspath.relative(PathsConstants_1.default.getApplicationPath(),e.opts.filename)+".dtx.downstream"),fs.mkdirSync(fspath.dirname(e),{recursive:!0}),fs.writeFileSync(e,t))}}};
@@ -1,12 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RootWrapper = exports.wrapProvider = exports.notifyPress = void 0;
3
+ exports.RootWrapper = exports.wrapProvider = exports.notifyPress = exports.UserInteractionEventKey = void 0;
4
4
  const React = require("react");
5
5
  const react_native_1 = require("react-native");
6
- const ConfigurationHandler_1 = require("../../lib/core/configuration/ConfigurationHandler");
7
6
  const EventPipeline_1 = require("../../lib/next/events/EventPipeline");
8
7
  const EventTimestamp_1 = require("../../lib/next/events/EventTimestamp");
9
8
  const TimestampProvider_1 = require("../../lib/next/provider/TimestampProvider");
9
+ const ConfigurationHandler_1 = require("../../lib/core/configuration/ConfigurationHandler");
10
+ var UserInteractionEventKey;
11
+ (function (UserInteractionEventKey) {
12
+ UserInteractionEventKey["EventHasUserInteraction"] = "characteristics.has_user_interaction";
13
+ UserInteractionEventKey["UiElementDetectedName"] = "ui_element.detected_name";
14
+ UserInteractionEventKey["UiElementComponents"] = "ui_element.components";
15
+ UserInteractionEventKey["UiElementId"] = "ui_element.id";
16
+ UserInteractionEventKey["UiElementNameOrigin"] = "ui_element.name_origin";
17
+ UserInteractionEventKey["InteractionType"] = "interaction.type";
18
+ UserInteractionEventKey["UiElementResponderDetectedName"] = "ui_element.responder.detected_name";
19
+ UserInteractionEventKey["UiElementResponderComponents"] = "ui_element.responder.components";
20
+ UserInteractionEventKey["UiElementResponderOriginName"] = "ui_element.responder.name_origin";
21
+ UserInteractionEventKey["UiElementResponderId"] = "ui_element.responder.id";
22
+ })(UserInteractionEventKey = exports.UserInteractionEventKey || (exports.UserInteractionEventKey = {}));
10
23
  const TOUCH_FLUSH_DELAY = 250;
11
24
  let pendingTouch = null;
12
25
  const getFiberPath = (fiber) => {
@@ -43,7 +56,7 @@ function findRCTTextChild(fiber) {
43
56
  return null;
44
57
  }
45
58
  const getHostComponentInfo = (event) => {
46
- var _a, _b;
59
+ var _a, _b, _c, _d, _e;
47
60
  let fiber = event._targetInst;
48
61
  if (!fiber) {
49
62
  console.warn('Assumption violated: _targetInst not found');
@@ -64,7 +77,7 @@ const getHostComponentInfo = (event) => {
64
77
  let detectedName;
65
78
  if (fiber.type !== 'RCTText') {
66
79
  nameOrigin = 'component';
67
- detectedName = (_b = fiber.memoizedProps.accessibilityLabel) !== null && _b !== void 0 ? _b : leaf;
80
+ detectedName = (_c = (_b = fiber.memoizedProps) === null || _b === void 0 ? void 0 : _b.accessibilityLabel) !== null && _c !== void 0 ? _c : leaf;
68
81
  }
69
82
  else if (anyParentMasked) {
70
83
  nameOrigin = 'masked';
@@ -72,7 +85,7 @@ const getHostComponentInfo = (event) => {
72
85
  }
73
86
  else {
74
87
  nameOrigin = 'text';
75
- detectedName = flatten(fiber.memoizedProps.children);
88
+ detectedName = flatten((_e = (_d = fiber.memoizedProps) === null || _d === void 0 ? void 0 : _d.children) !== null && _e !== void 0 ? _e : '');
76
89
  }
77
90
  return { id, components, detectedName, nameOrigin };
78
91
  };
@@ -92,8 +105,9 @@ const flushTouch = (responderComponentInfo) => {
92
105
  EventPipeline_1.EventPipeline.insertEvent(event);
93
106
  };
94
107
  const onTouch = (e) => {
95
- if (!ConfigurationHandler_1.ConfigurationHandler.isUserInteractionEnabled())
108
+ if (!ConfigurationHandler_1.ConfigurationHandler.getThirdGenDataReportingDecision().allowed) {
96
109
  return;
110
+ }
97
111
  flushTouch();
98
112
  const touchedComponentInfo = getHostComponentInfo(e);
99
113
  if (!touchedComponentInfo)
@@ -0,0 +1,94 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SectionList = exports.FlatList = exports.useTableReloadOnChange = void 0;
4
+ const react_native_1 = require("react-native");
5
+ const React = require("react");
6
+ const TableReloadTracker_1 = require("../../../lib/next/triggers/TableReloadTracker");
7
+ const ConsoleLogger_1 = require("../../../lib/core/logging/ConsoleLogger");
8
+ const LogMessages_1 = require("../../../lib/core/logging/LogMessages");
9
+ const DEBOUNCE_MS = 100;
10
+ const logger = new ConsoleLogger_1.ConsoleLogger('TableReload');
11
+ const _useIsFocused = (() => {
12
+ try {
13
+ return require('@react-navigation/native').useIsFocused;
14
+ }
15
+ catch (_a) {
16
+ return () => true;
17
+ }
18
+ })();
19
+ function useTableReloadOnChange(value, label) {
20
+ const isFocused = _useIsFocused();
21
+ const isFocusedRef = React.useRef(isFocused);
22
+ const isMounted = React.useRef(false);
23
+ const pendingReload = React.useRef(false);
24
+ const timer = React.useRef(null);
25
+ React.useEffect(() => {
26
+ isFocusedRef.current = isFocused;
27
+ }, [isFocused]);
28
+ const fireAfterDebounce = React.useCallback(() => {
29
+ if (timer.current !== null)
30
+ clearTimeout(timer.current);
31
+ timer.current = setTimeout(() => {
32
+ timer.current = null;
33
+ if (!isFocusedRef.current) {
34
+ logger.debug(LogMessages_1.LogMessage.TABLE_RELOAD_DEBOUNCE_LOST_FOCUS, {
35
+ label,
36
+ });
37
+ pendingReload.current = true;
38
+ return;
39
+ }
40
+ logger.debug(LogMessages_1.LogMessage.TABLE_RELOAD_DEBOUNCE_ELAPSED, { label });
41
+ (0, TableReloadTracker_1.callTableReloadTrigger)(Date.now());
42
+ }, DEBOUNCE_MS);
43
+ }, [label]);
44
+ React.useEffect(() => {
45
+ if (!isMounted.current) {
46
+ isMounted.current = true;
47
+ logger.debug(LogMessages_1.LogMessage.TABLE_RELOAD_MOUNTED, {
48
+ label,
49
+ length: Array.isArray(value) ? String(value.length) : 'null',
50
+ });
51
+ return;
52
+ }
53
+ const length = Array.isArray(value) ? String(value.length) : 'null';
54
+ if (!isFocused) {
55
+ logger.debug(LogMessages_1.LogMessage.TABLE_RELOAD_DATA_CHANGED_NOT_FOCUSED, {
56
+ label,
57
+ length,
58
+ });
59
+ pendingReload.current = true;
60
+ return;
61
+ }
62
+ logger.debug(LogMessages_1.LogMessage.TABLE_RELOAD_DATA_CHANGED, { label, length });
63
+ pendingReload.current = false;
64
+ fireAfterDebounce();
65
+ return () => {
66
+ if (timer.current !== null) {
67
+ clearTimeout(timer.current);
68
+ timer.current = null;
69
+ }
70
+ };
71
+ }, [value]);
72
+ React.useEffect(() => {
73
+ if (!isFocused || !pendingReload.current)
74
+ return;
75
+ pendingReload.current = false;
76
+ logger.debug(LogMessages_1.LogMessage.TABLE_RELOAD_FOCUS_RESTORED, { label });
77
+ fireAfterDebounce();
78
+ return () => {
79
+ if (timer.current !== null) {
80
+ clearTimeout(timer.current);
81
+ timer.current = null;
82
+ }
83
+ };
84
+ }, [isFocused, fireAfterDebounce, label]);
85
+ }
86
+ exports.useTableReloadOnChange = useTableReloadOnChange;
87
+ exports.FlatList = React.forwardRef(function DynatraceFlatList(props, ref) {
88
+ useTableReloadOnChange(props.data, 'FlatList');
89
+ return React.createElement(react_native_1.FlatList, Object.assign({ ref: ref }, props));
90
+ });
91
+ exports.SectionList = React.forwardRef(function DynatraceSectionList(props, ref) {
92
+ useTableReloadOnChange(props.sections, 'SectionList');
93
+ return React.createElement(react_native_1.SectionList, Object.assign({ ref: ref }, props));
94
+ });
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Switch = exports.Pressable = exports.Text = exports.Button = exports.TouchableWithoutFeedback = exports.TouchableOpacity = exports.TouchableNativeFeedback = exports.TouchableHighlight = exports.RefreshControl = void 0;
3
+ exports.SectionList = exports.FlatList = exports.Switch = exports.Pressable = exports.Text = exports.Button = exports.TouchableWithoutFeedback = exports.TouchableOpacity = exports.TouchableNativeFeedback = exports.TouchableHighlight = exports.RefreshControl = void 0;
4
4
  var RefreshControl_1 = require("./RefreshControl");
5
5
  Object.defineProperty(exports, "RefreshControl", { enumerable: true, get: function () { return RefreshControl_1.RefreshControl; } });
6
6
  var Touchables_1 = require("./Touchables");
@@ -13,3 +13,6 @@ Object.defineProperty(exports, "Text", { enumerable: true, get: function () { re
13
13
  Object.defineProperty(exports, "Pressable", { enumerable: true, get: function () { return Touchables_1.Pressable; } });
14
14
  var Switch_1 = require("./Switch");
15
15
  Object.defineProperty(exports, "Switch", { enumerable: true, get: function () { return Switch_1.Switch; } });
16
+ var Lists_1 = require("./Lists");
17
+ Object.defineProperty(exports, "FlatList", { enumerable: true, get: function () { return Lists_1.FlatList; } });
18
+ Object.defineProperty(exports, "SectionList", { enumerable: true, get: function () { return Lists_1.SectionList; } });
@@ -5,6 +5,7 @@ const reactNative = require("react-native");
5
5
  const Touchables_1 = require("./react-native/Touchables");
6
6
  const RefreshControl_1 = require("./react-native/RefreshControl");
7
7
  const Switch_1 = require("./react-native/Switch");
8
+ const Lists_1 = require("./react-native/Lists");
8
9
  const dynatraceInstrument = {
9
10
  TouchableHighlight: Touchables_1.TouchableHighlight,
10
11
  TouchableNativeFeedback: Touchables_1.TouchableNativeFeedback,
@@ -15,6 +16,8 @@ const dynatraceInstrument = {
15
16
  Text: Touchables_1.Text,
16
17
  Pressable: Touchables_1.Pressable,
17
18
  Switch: Switch_1.Switch,
19
+ FlatList: Lists_1.FlatList,
20
+ SectionList: Lists_1.SectionList,
18
21
  };
19
22
  const dynatraceProxy = new Proxy(reactNative, {
20
23
  get: (target, property) => {
@@ -1,74 +1,30 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.monitorNavigation = void 0;
3
+ exports.useNavigationMonitor = void 0;
4
4
  const react_1 = require("react");
5
5
  const react_native_1 = require("react-native");
6
- const ConsoleLogger_1 = require("../../../lib/core/logging/ConsoleLogger");
7
- const LogMessages_1 = require("../../../lib/core/logging/LogMessages");
8
- const DynatraceBridge_1 = require("../../../lib/core/DynatraceBridge");
9
- const BaseDataEventModifier_1 = require("../../../lib/next/events/modifier/BaseDataEventModifier");
10
- const ConfigurationHandler_1 = require("../../../lib/core/configuration/ConfigurationHandler");
11
- const logger = new ConsoleLogger_1.ConsoleLogger('ReactNavigation');
12
- let activePath = '';
13
- let appState = react_native_1.AppState.currentState;
14
- const monitorNavigation = (getRootState) => {
6
+ const NavigationTracker_1 = require("../../../lib/next/navigation/NavigationTracker");
7
+ const useNavigationMonitor = (getRootState) => {
15
8
  (0, react_1.useEffect)(() => {
16
- var _a, _b;
17
- let currentState = getRootState();
18
- let newPath = '';
19
- while (currentState === null || currentState === void 0 ? void 0 : currentState.routes[(_a = currentState.index) !== null && _a !== void 0 ? _a : 0]) {
20
- const currentRoute = currentState === null || currentState === void 0 ? void 0 : currentState.routes[(_b = currentState.index) !== null && _b !== void 0 ? _b : 0];
21
- newPath += `/${currentRoute.name}`;
22
- currentState = currentRoute.state;
23
- }
24
- if (newPath !== activePath) {
25
- if (activePath !== '') {
26
- stopView();
27
- }
28
- startView(newPath);
29
- activePath = newPath;
30
- }
9
+ const newPath = (0, NavigationTracker_1.buildPathFromState)(getRootState());
10
+ (0, NavigationTracker_1.reportScreenChange)(newPath);
31
11
  });
12
+ const appStateRef = (0, react_1.useRef)(react_native_1.AppState.currentState);
32
13
  (0, react_1.useEffect)(() => {
33
14
  const subscription = react_native_1.AppState.addEventListener('change', (nextAppState) => {
34
- if (nextAppState !== 'active' && appState === 'active') {
35
- stopView();
15
+ const prevAppState = appStateRef.current;
16
+ appStateRef.current = nextAppState;
17
+ if (nextAppState !== 'active' && prevAppState === 'active') {
18
+ (0, NavigationTracker_1.reportScreenBackground)();
36
19
  }
37
- else if (nextAppState === 'active' && appState !== 'active') {
38
- startView(activePath);
20
+ else if (nextAppState === 'active' &&
21
+ prevAppState !== 'active') {
22
+ (0, NavigationTracker_1.reportScreenResume)();
39
23
  }
40
- appState = nextAppState;
41
24
  });
42
25
  return () => {
43
26
  subscription.remove();
44
27
  };
45
28
  }, []);
46
29
  };
47
- exports.monitorNavigation = monitorNavigation;
48
- const startView = (newPath) => {
49
- if (!ConfigurationHandler_1.ConfigurationHandler.isConfigurationAvailable()) {
50
- logger.info(LogMessages_1.LogMessage.NAVIGATION_NOT_STARTED);
51
- return;
52
- }
53
- const startViewInternalEvent = new BaseDataEventModifier_1.BaseDataEventModifier().modifyEvent(Object.assign({ 'view.detected_name': newPath }, (activePath && {
54
- 'view.source.detected_name': activePath,
55
- })));
56
- const fn = DynatraceBridge_1.DynatraceNative === null || DynatraceBridge_1.DynatraceNative === void 0 ? void 0 : DynatraceBridge_1.DynatraceNative.startViewInternal;
57
- if (typeof fn === 'function') {
58
- fn(startViewInternalEvent);
59
- }
60
- logger.debug(LogMessages_1.LogMessage.START_VIEW_INTERNAL, {
61
- event: JSON.stringify(startViewInternalEvent),
62
- });
63
- };
64
- const stopView = () => {
65
- if (!ConfigurationHandler_1.ConfigurationHandler.isConfigurationAvailable()) {
66
- logger.info(LogMessages_1.LogMessage.NAVIGATION_NOT_STARTED);
67
- return;
68
- }
69
- const fn = DynatraceBridge_1.DynatraceNative === null || DynatraceBridge_1.DynatraceNative === void 0 ? void 0 : DynatraceBridge_1.DynatraceNative.stopViewInternal;
70
- if (typeof fn === 'function') {
71
- fn();
72
- }
73
- logger.debug(LogMessages_1.LogMessage.STOP_VIEW_INTERNAL);
74
- };
30
+ exports.useNavigationMonitor = useNavigationMonitor;
@@ -15,68 +15,18 @@ function withOnPressMonitoring(Component, fallbackName) {
15
15
  const { onPress, onLongPress } = props;
16
16
  const touchableName = (0, exports.chooseTouchableName)(props, fallbackName);
17
17
  const dynatraceIgnored = (0, ComponentUtil_1.isDynatraceIgnored)(props);
18
- const isRNButton = 'title' in props && typeof props.title === 'string';
19
- const isRectButton = fallbackName === 'Button';
20
- const isButtonLike = isRNButton || isRectButton;
21
- const buttonLabel = isRNButton ? String(props.title) : null;
22
18
  const propsWithoutRef = Object.assign(Object.assign(Object.assign({}, props), (!dynatraceIgnored &&
23
19
  onPress && {
24
- onPress: (0, exports.wrapOnPress)(onPress, touchableName, isButtonLike, buttonLabel),
20
+ onPress: (0, exports.wrapOnPress)(onPress, touchableName),
25
21
  })), (!dynatraceIgnored &&
26
22
  onLongPress && {
27
- onLongPress: (0, exports.wrapOnPress)(onLongPress, touchableName, isButtonLike, buttonLabel),
23
+ onLongPress: (0, exports.wrapOnPress)(onLongPress, touchableName),
28
24
  }));
29
25
  const propsWithRef = Object.assign(Object.assign({}, propsWithoutRef), { ref });
30
26
  return React.createElement(Component, Object.assign({}, propsWithRef));
31
27
  });
32
28
  }
33
29
  exports.withOnPressMonitoring = withOnPressMonitoring;
34
- const dtGetUiBridge = () => {
35
- var _a;
36
- const g = globalThis;
37
- return (_a = g === null || g === void 0 ? void 0 : g.__DT_UII_BRIDGE) !== null && _a !== void 0 ? _a : null;
38
- };
39
- const dtBuildPressPath = (startPath, touchableName) => {
40
- var _a;
41
- const base = (_a = startPath === null || startPath === void 0 ? void 0 : startPath.toString()) !== null && _a !== void 0 ? _a : '';
42
- if (!base)
43
- return `Touchable(${touchableName})`;
44
- const cut1 = base.lastIndexOf('/Text');
45
- const cut2 = base.lastIndexOf('/Text(');
46
- const cut = Math.max(cut1, cut2);
47
- const parent = cut > 0 ? base.slice(0, cut) : base;
48
- return parent + `/Touchable(${touchableName})`;
49
- };
50
- const registerPressOnBridge = (args, touchableName, isButtonLike, buttonLabel) => {
51
- const bridge = dtGetUiBridge();
52
- if (!bridge || typeof bridge.registerPress !== 'function') {
53
- return;
54
- }
55
- try {
56
- const e = args === null || args === void 0 ? void 0 : args[0];
57
- const ne = e === null || e === void 0 ? void 0 : e.nativeEvent;
58
- const x = Number(ne === null || ne === void 0 ? void 0 : ne.pageX);
59
- const y = Number(ne === null || ne === void 0 ? void 0 : ne.pageY);
60
- const pos = Number.isFinite(x) && Number.isFinite(y) ? { x, y } : undefined;
61
- const startPath = typeof bridge.getStartPath === 'function'
62
- ? bridge.getStartPath()
63
- : null;
64
- const nameForBridge = isButtonLike
65
- ? buttonLabel || touchableName
66
- : touchableName;
67
- bridge.registerPress({
68
- path: dtBuildPressPath(startPath, nameForBridge),
69
- elementName: nameForBridge,
70
- pos,
71
- });
72
- }
73
- catch (e) {
74
- const errorMsg = e instanceof Error ? e.stack || e.message : String(e);
75
- Logger.debug(LogMessages_1.LogMessage.REGISTER_PRESS_HOOK_FAILED, {
76
- errorMsg,
77
- });
78
- }
79
- };
80
30
  const notifyPressFromEvent = (args) => {
81
31
  if (args[0] && typeof args[0] === 'object' && 'nativeEvent' in args[0]) {
82
32
  (0, UserInteraction_1.notifyPress)(args[0]);
@@ -104,9 +54,8 @@ const invokeOnPressWithAction = (onPress, args, touchableName) => {
104
54
  }
105
55
  }
106
56
  };
107
- const wrapOnPress = (onPress, touchableName, isButtonLike, buttonLabel) => {
57
+ const wrapOnPress = (onPress, touchableName) => {
108
58
  return (...args) => {
109
- registerPressOnBridge(args, touchableName, isButtonLike, buttonLabel);
110
59
  notifyPressFromEvent(args);
111
60
  if (!ConfigurationHandler_1.ConfigurationHandler.isConfigurationAvailable()) {
112
61
  invokeOnPressWithoutConfiguration(onPress, args);
package/internal.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export declare function registerNavigationEventTrigger(fn: ((name: string, timestamp: number) => void) | null): void;
2
+ export declare function registerTableReloadTrigger(fn: ((timestamp: number) => void) | null): void;
package/internal.js CHANGED
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.createElement = exports.ApplicationHandler = void 0;
3
+ exports.registerTableReloadTrigger = exports.registerNavigationEventTrigger = exports.createElement = exports.ApplicationHandler = void 0;
4
4
  var Application_1 = require("./lib/core/Application");
5
5
  Object.defineProperty(exports, "ApplicationHandler", { enumerable: true, get: function () { return Application_1.ApplicationHandler; } });
6
6
  var CreateElement_1 = require("./instrumentation/jsx/CreateElement");
7
7
  Object.defineProperty(exports, "createElement", { enumerable: true, get: function () { return CreateElement_1.createElement; } });
8
+ var NavigationTracker_1 = require("./lib/next/navigation/NavigationTracker");
9
+ Object.defineProperty(exports, "registerNavigationEventTrigger", { enumerable: true, get: function () { return NavigationTracker_1.registerNavigationEventTrigger; } });
10
+ var TableReloadTracker_1 = require("./lib/next/triggers/TableReloadTracker");
11
+ Object.defineProperty(exports, "registerTableReloadTrigger", { enumerable: true, get: function () { return TableReloadTracker_1.registerTableReloadTrigger; } });