@nordicsemiconductor/pc-nrfconnect-shared 149.0.0 → 151.0.0

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 (64) hide show
  1. package/Changelog.md +45 -1
  2. package/ipc/infrastructure/mainToRenderer.ts +4 -0
  3. package/main/index.ts +4 -1
  4. package/nrfutil/sandbox.ts +10 -6
  5. package/package.json +2 -2
  6. package/src/App/App.test.tsx +11 -2
  7. package/src/App/App.tsx +3 -3
  8. package/src/Device/DeviceSelector/DeviceSelector.test.tsx +13 -0
  9. package/src/Device/DeviceSelector/DeviceSelector.tsx +6 -6
  10. package/src/Device/deviceLister.ts +4 -4
  11. package/src/ErrorBoundary/ErrorBoundary.test.tsx +5 -5
  12. package/src/ErrorBoundary/ErrorBoundary.tsx +14 -13
  13. package/src/Overlay/overlay.scss +6 -7
  14. package/src/Parsers/shellParser.ts +3 -3
  15. package/src/index.ts +2 -2
  16. package/src/telemetry/TelemetryMetadata.ts +9 -0
  17. package/src/telemetry/TelemetrySender.ts +80 -0
  18. package/src/telemetry/TelemetrySenderInMain.ts +80 -0
  19. package/src/telemetry/TelemetrySenderInRenderer.ts +86 -0
  20. package/src/telemetry/flatObject.test.ts +37 -0
  21. package/src/telemetry/flatObject.ts +19 -0
  22. package/src/telemetry/simplifyDevice.ts +20 -0
  23. package/src/telemetry/telemetry.ts +97 -0
  24. package/src/utils/persistentStore.ts +7 -7
  25. package/src/utils/systemReport.ts +1 -1
  26. package/src/utils/useHotKey.ts +2 -2
  27. package/typings/generated/ipc/infrastructure/mainToRenderer.d.ts +1 -0
  28. package/typings/generated/ipc/infrastructure/mainToRenderer.d.ts.map +1 -1
  29. package/typings/generated/main/index.d.ts +1 -1
  30. package/typings/generated/main/index.d.ts.map +1 -1
  31. package/typings/generated/nrfutil/sandbox.d.ts.map +1 -1
  32. package/typings/generated/src/ErrorBoundary/ErrorBoundary.d.ts +1 -1
  33. package/typings/generated/src/ErrorBoundary/ErrorBoundary.d.ts.map +1 -1
  34. package/typings/generated/src/index.d.ts +2 -2
  35. package/typings/generated/src/index.d.ts.map +1 -1
  36. package/typings/generated/src/telemetry/TelemetryMetadata.d.ts +4 -0
  37. package/typings/generated/src/telemetry/TelemetryMetadata.d.ts.map +1 -0
  38. package/typings/generated/src/telemetry/TelemetrySender.d.ts +24 -0
  39. package/typings/generated/src/telemetry/TelemetrySender.d.ts.map +1 -0
  40. package/typings/generated/src/telemetry/TelemetrySenderInMain.d.ts +15 -0
  41. package/typings/generated/src/telemetry/TelemetrySenderInMain.d.ts.map +1 -0
  42. package/typings/generated/src/telemetry/TelemetrySenderInRenderer.d.ts +15 -0
  43. package/typings/generated/src/telemetry/TelemetrySenderInRenderer.d.ts.map +1 -0
  44. package/typings/generated/src/telemetry/flatObject.d.ts +4 -0
  45. package/typings/generated/src/telemetry/flatObject.d.ts.map +1 -0
  46. package/typings/generated/src/telemetry/flatObject.test.d.ts +2 -0
  47. package/typings/generated/src/telemetry/flatObject.test.d.ts.map +1 -0
  48. package/typings/generated/src/{utils/usageDataCommon.d.ts → telemetry/simplifyDevice.d.ts} +2 -14
  49. package/typings/generated/src/telemetry/simplifyDevice.d.ts.map +1 -0
  50. package/typings/generated/src/telemetry/telemetry.d.ts +16 -0
  51. package/typings/generated/src/telemetry/telemetry.d.ts.map +1 -0
  52. package/typings/generated/src/utils/persistentStore.d.ts +4 -4
  53. package/typings/generated/src/utils/persistentStore.d.ts.map +1 -1
  54. package/src/utils/usageData.ts +0 -117
  55. package/src/utils/usageDataCommon.ts +0 -59
  56. package/src/utils/usageDataMain.ts +0 -119
  57. package/src/utils/usageDataRenderer.ts +0 -137
  58. package/typings/generated/src/utils/usageData.d.ts +0 -16
  59. package/typings/generated/src/utils/usageData.d.ts.map +0 -1
  60. package/typings/generated/src/utils/usageDataCommon.d.ts.map +0 -1
  61. package/typings/generated/src/utils/usageDataMain.d.ts +0 -10
  62. package/typings/generated/src/utils/usageDataMain.d.ts.map +0 -1
  63. package/typings/generated/src/utils/usageDataRenderer.d.ts +0 -10
  64. package/typings/generated/src/utils/usageDataRenderer.d.ts.map +0 -1
package/Changelog.md CHANGED
@@ -7,6 +7,50 @@ This project does _not_ adhere to
7
7
  [Semantic Versioning](https://semver.org/spec/v2.0.0.html) but contrary to it
8
8
  every new version is a new major version.
9
9
 
10
+ ## 151.0.0 - 2024-01-23
11
+
12
+ ### Changed
13
+
14
+ - Renamed exported object `usageData` to `telemetry` and type
15
+ `UsageDataMetadata` to `TelemetryMetadata`.
16
+ - Renamed several function in the `telemetry` object:
17
+ - `enable()` → `setUsersAgreedToTelemetry(true)`
18
+ - `disable()` → `setUsersAgreedToTelemetry(false)`
19
+ - `reset()` → `setUsersWithdrewTelemetryAgreement()`
20
+ - `isEnabled()` → `getIsSendingTelemetry()` (which now does not log
21
+ anymore)
22
+ - `sendUsageData()` → `sendEvent()`
23
+ - In the component `ErrorBoundary` the property `sendUsageData` is renamed to
24
+ `sendTelemetryEvent`.
25
+
26
+ ### Steps to upgrade when using this package
27
+
28
+ - If they are imported from shared, rename `usageData` and `UsageDataMetadata`
29
+ as well as the renamed functions mentioned above.
30
+ - In usages of the component `ErrorBoundary`, rename the property
31
+ `sendUsageData` to `sendTelemetryEvent`.
32
+
33
+ ## 150.0.0 - 2024-01-18
34
+
35
+ ### Removed
36
+
37
+ - `Overlay` tooltip inner padding should be set by the content within it.
38
+
39
+ ### Added
40
+
41
+ - Ability to remove the launcher window again. This is especially needed on
42
+ shutdown. Otherwise when at that time someone still tries to send IPC
43
+ messages to the launcher window, an exception is thrown.
44
+
45
+ ### Fixed
46
+
47
+ - `Overlay` tooltips weren't centered due to incorrect sizing styles.
48
+ - When spawning the nrfutil process fails in certain ways, an uncaught
49
+ exception in the main process got thrown. The “certain ways” make this a bit
50
+ hard to reproduce: On macOS this happened, when the nrfutil executable did
51
+ not have the executable file mode. Usually this should not happen, because
52
+ we set that mode ourselves correctly.
53
+
10
54
  ## 149.0.0 - 2024-01-16
11
55
 
12
56
  ### Added
@@ -195,7 +239,7 @@ every new version is a new major version.
195
239
 
196
240
  ### Fixed
197
241
 
198
- - Telemtry: Metadata was not removed on request, when being in the main
242
+ - Telemetry: Metadata was not removed on request, when being in the main
199
243
  process. This is not critical because this code isn't yet executed in real
200
244
  life.
201
245
 
@@ -12,6 +12,10 @@ export const registerLauncherWindowFromMain = (window: BrowserWindow) => {
12
12
  launcherWindow = window;
13
13
  };
14
14
 
15
+ export const removeLauncherWindowFromMain = () => {
16
+ launcherWindow = undefined;
17
+ };
18
+
15
19
  export const send =
16
20
  <T extends (...args: never[]) => void>(channel: string) =>
17
21
  (...args: Parameters<T>) =>
package/main/index.ts CHANGED
@@ -15,7 +15,10 @@ import {
15
15
  inRenderer as inRendererSerialPort,
16
16
  } from '../ipc/serialPort';
17
17
 
18
- export { registerLauncherWindowFromMain } from '../ipc/infrastructure/mainToRenderer';
18
+ export {
19
+ registerLauncherWindowFromMain,
20
+ removeLauncherWindowFromMain,
21
+ } from '../ipc/infrastructure/mainToRenderer';
19
22
 
20
23
  export const appDetails = { forRenderer: forRendererAppDetails };
21
24
  export const apps = { forRenderer: forRendererApps };
@@ -11,8 +11,8 @@ import path from 'path';
11
11
  import treeKill from 'tree-kill';
12
12
 
13
13
  import describeError from '../src/logging/describeError';
14
+ import telemetry from '../src/telemetry/telemetry';
14
15
  import { isDevelopment } from '../src/utils/environment';
15
- import usageData from '../src/utils/usageData';
16
16
  import { versionToInstall } from './moduleVersion';
17
17
  import { getNrfutilLogger } from './nrfutilLogger';
18
18
  import {
@@ -313,7 +313,7 @@ export class NrfutilSandbox {
313
313
  }
314
314
 
315
315
  error.message = error.message.replaceAll('Error: ', '');
316
- usageData.sendErrorReport(
316
+ telemetry.sendErrorReport(
317
317
  `${
318
318
  pid && this.logLevel === 'trace' ? `[PID:${pid}] ` : ''
319
319
  }${describeError(error)}`
@@ -332,7 +332,7 @@ export class NrfutilSandbox {
332
332
  ) =>
333
333
  new Promise<void>((resolve, reject) => {
334
334
  let aborting = false;
335
- usageData.sendUsageData(`running nrfutil ${this.module}`, {
335
+ telemetry.sendEvent(`running nrfutil ${this.module}`, {
336
336
  args,
337
337
  exec: command,
338
338
  });
@@ -374,6 +374,10 @@ export class NrfutilSandbox {
374
374
  onStdError(data, nrfutil.pid);
375
375
  });
376
376
 
377
+ nrfutil.on('error', err => {
378
+ reject(err);
379
+ });
380
+
377
381
  nrfutil.on('close', code => {
378
382
  controller?.signal.removeEventListener('abort', listener);
379
383
  if (aborting) {
@@ -490,7 +494,7 @@ export class NrfutilSandbox {
490
494
  }
491
495
 
492
496
  error.message = error.message.replaceAll('Error: ', '');
493
- usageData.sendErrorReport(
497
+ telemetry.sendErrorReport(
494
498
  `${
495
499
  pid && this.logLevel === 'trace' ? `[PID:${pid}] ` : ''
496
500
  }${describeError(error)}`
@@ -509,7 +513,7 @@ export class NrfutilSandbox {
509
513
  ) =>
510
514
  new Promise<void>((resolve, reject) => {
511
515
  let aborting = false;
512
- usageData.sendUsageData(`running nrfutil ${this.module}`, {
516
+ telemetry.sendEvent(`running nrfutil ${this.module}`, {
513
517
  args,
514
518
  exec: command,
515
519
  });
@@ -607,7 +611,7 @@ export class NrfutilSandbox {
607
611
  closedHandlers.forEach(callback => callback());
608
612
  })
609
613
  .catch(error => {
610
- usageData.sendErrorReport(describeError(error));
614
+ telemetry.sendErrorReport(describeError(error));
611
615
  running = false;
612
616
  closedHandlers.forEach(callback => callback(error));
613
617
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nordicsemiconductor/pc-nrfconnect-shared",
3
- "version": "149.0.0",
3
+ "version": "151.0.0",
4
4
  "description": "Shared commodities for developing pc-nrfconnect-* packages",
5
5
  "repository": {
6
6
  "type": "git",
@@ -25,7 +25,7 @@
25
25
  "prepare": "ts-node scripts/installHusky.ts",
26
26
  "release-shared": "ts-node scripts/release-shared.ts",
27
27
  "prepare-shared-release": "ts-node scripts/prepare-shared-release.ts",
28
- "clean": "rimraf dist typings/generated dist scripts/nordic-publish.js",
28
+ "clean": "rimraf dist typings/generated scripts/nordic-publish.js",
29
29
  "postinstall": "ts-node scripts/postinstall.ts"
30
30
  },
31
31
  "dependencies": {
@@ -5,8 +5,9 @@
5
5
  */
6
6
 
7
7
  import React from 'react';
8
- import { screen } from '@testing-library/react';
8
+ import { act, screen } from '@testing-library/react';
9
9
 
10
+ import { OFFICIAL } from '../../ipc/sources';
10
11
  import packageJsonFromShared from '../../package.json';
11
12
  import render from '../../test/testrenderer';
12
13
  import App, { Pane } from './App';
@@ -26,6 +27,12 @@ jest.mock('../utils/packageJson', () => ({
26
27
  packageJson: () => packageJsonFromShared,
27
28
  }));
28
29
 
30
+ const appDetails = Promise.resolve({ source: OFFICIAL });
31
+ jest.mock('../utils/appDetails', () => ({
32
+ __esModule: true,
33
+ default: () => appDetails,
34
+ }));
35
+
29
36
  const renderApp = (panes: Pane[]) => {
30
37
  const dummyReducer = (s = null) => s;
31
38
  const dummyNode = <div />;
@@ -50,9 +57,11 @@ const anotherPane = {
50
57
  };
51
58
 
52
59
  describe('App', () => {
53
- it('automatically gets an About pane attached', () => {
60
+ it('automatically gets an About pane attached', async () => {
54
61
  renderApp([aPane, anotherPane]);
55
62
 
56
63
  expect(screen.getByText('About')).toBeInTheDocument();
64
+
65
+ await act(() => appDetails);
57
66
  });
58
67
  });
package/src/App/App.tsx CHANGED
@@ -29,12 +29,12 @@ import FlashMessages from '../FlashMessage/FlashMessage';
29
29
  import LogViewer from '../Log/LogViewer';
30
30
  import logger from '../logging';
31
31
  import NavBar from '../NavBar/NavBar';
32
+ import telemetry from '../telemetry/telemetry';
32
33
  import classNames from '../utils/classNames';
33
34
  import {
34
35
  getPersistedCurrentPane,
35
36
  getPersistedLogVisible,
36
37
  } from '../utils/persistentStore';
37
- import usageData from '../utils/usageData';
38
38
  import useHotKey from '../utils/useHotKey';
39
39
  import {
40
40
  currentPane as currentPaneSelector,
@@ -87,7 +87,7 @@ const ConnectedApp: FC<ConnectedAppProps> = ({
87
87
  if (!initApp.current) {
88
88
  logger.initialise();
89
89
  setNrfutilLogger(logger);
90
- usageData.setLogger(logger);
90
+ telemetry.setLogger(logger);
91
91
  initApp.current = true;
92
92
  }
93
93
 
@@ -110,7 +110,7 @@ const ConnectedApp: FC<ConnectedAppProps> = ({
110
110
  }, [allPanes]);
111
111
 
112
112
  useEffect(() => {
113
- usageData.sendPageView(paneName.current[currentPane]);
113
+ telemetry.sendPageView(paneName.current[currentPane]);
114
114
  }, [currentPane]);
115
115
 
116
116
  useEffect(() => {
@@ -7,6 +7,8 @@
7
7
  import React from 'react';
8
8
  import { act, fireEvent, screen, waitFor } from '@testing-library/react';
9
9
 
10
+ import { OFFICIAL } from '../../../ipc/sources';
11
+ import packageJsonFromShared from '../../../package.json';
10
12
  import render from '../../../test/testrenderer';
11
13
  import { addDevice, Device, removeDevice } from '../deviceSlice';
12
14
  import { jprogDeviceSetup } from '../jprogOperations';
@@ -14,6 +16,17 @@ import DeviceSelector from './DeviceSelector';
14
16
 
15
17
  jest.mock('../../../nrfutil/device/device');
16
18
 
19
+ jest.mock('../../utils/packageJson', () => ({
20
+ isLauncher: () => false,
21
+ packageJson: () => packageJsonFromShared,
22
+ }));
23
+
24
+ const appDetails = Promise.resolve({ source: OFFICIAL });
25
+ jest.mock('../../utils/appDetails', () => ({
26
+ __esModule: true,
27
+ default: () => appDetails,
28
+ }));
29
+
17
30
  const DEVICE_SERIAL_NUMBER = '000000001';
18
31
 
19
32
  const testDevice: Device = {
@@ -10,8 +10,8 @@ import { useDispatch, useSelector } from 'react-redux';
10
10
  import { NrfutilDeviceLib } from '../../../nrfutil/device';
11
11
  import { DeviceTraits } from '../../../nrfutil/device/common';
12
12
  import logger from '../../logging';
13
- import usageData from '../../utils/usageData';
14
- import { simplifyDeviceForLogging } from '../../utils/usageDataCommon';
13
+ import simplifyDevice from '../../telemetry/simplifyDevice';
14
+ import telemetry from '../../telemetry/telemetry';
15
15
  import useHotKey from '../../utils/useHotKey';
16
16
  import {
17
17
  clearWaitForDevice,
@@ -71,9 +71,9 @@ export default ({
71
71
  const doDeselectDevice = useCallback(
72
72
  (device?: Device) => {
73
73
  if (device) {
74
- usageData.sendUsageData(
74
+ telemetry.sendEvent(
75
75
  'device deselected ',
76
- simplifyDeviceForLogging(device)
76
+ simplifyDevice(device)
77
77
  );
78
78
  }
79
79
 
@@ -120,8 +120,8 @@ export default ({
120
120
  dispatch(setSelectedDeviceInfo(deviceInfo));
121
121
  onDeviceSelected(device, autoReselected);
122
122
 
123
- usageData.sendUsageData('device selected', {
124
- device: simplifyDeviceForLogging(device),
123
+ telemetry.sendEvent('device selected', {
124
+ device: simplifyDevice(device),
125
125
  deviceInfo,
126
126
  });
127
127
 
@@ -9,8 +9,8 @@ import { DeviceTraits, NrfutilDevice } from '../../nrfutil/device/common';
9
9
  import NrfutilDeviceLib from '../../nrfutil/device/device';
10
10
  import logger from '../logging';
11
11
  import type { AppThunk, RootState } from '../store';
12
- import usageData from '../utils/usageData';
13
- import { simplifyDeviceForLogging } from '../utils/usageDataCommon';
12
+ import simplifyDevice from '../telemetry/simplifyDevice';
13
+ import telemetry from '../telemetry/telemetry';
14
14
  import {
15
15
  clearWaitForDevice,
16
16
  clearWaitForDeviceTimeout,
@@ -180,9 +180,9 @@ export const startWatchingDevices =
180
180
 
181
181
  const action = async (device: Device) => {
182
182
  if (hasValidDeviceTraits(device.traits, deviceListing)) {
183
- usageData.sendUsageData(
183
+ telemetry.sendEvent(
184
184
  'device connected',
185
- simplifyDeviceForLogging(device)
185
+ simplifyDevice(device)
186
186
  );
187
187
  if (
188
188
  !getState().device.devices.find(
@@ -13,8 +13,8 @@ import { generateSystemReport } from '../utils/systemReport';
13
13
  import ErrorBoundary from './ErrorBoundary';
14
14
 
15
15
  jest.mock('../utils/systemReport');
16
- jest.mock('../utils/usageData', () => ({
17
- ...jest.requireActual('../utils/usageData'),
16
+ jest.mock('../telemetry/telemetry', () => ({
17
+ ...jest.requireActual('../telemetry/telemetry'),
18
18
  sendErrorReport: jest.fn(),
19
19
  isEnabled: () => true,
20
20
  }));
@@ -44,14 +44,14 @@ describe('ErrorBoundary', () => {
44
44
  });
45
45
 
46
46
  it('can take custom reporting functions', () => {
47
- const sendUsageData = jest.fn();
47
+ const sendTelemetryEvent = jest.fn();
48
48
 
49
49
  render(
50
- <ErrorBoundary sendUsageData={sendUsageData}>
50
+ <ErrorBoundary sendTelemetryEvent={sendTelemetryEvent}>
51
51
  <Child />
52
52
  </ErrorBoundary>
53
53
  );
54
- expect(sendUsageData).toHaveBeenCalled();
54
+ expect(sendTelemetryEvent).toHaveBeenCalled();
55
55
  });
56
56
 
57
57
  it('should render error boundary component when there is an error', () => {
@@ -12,21 +12,17 @@ import { Device } from '../Device/deviceSlice';
12
12
  import FactoryResetButton from '../FactoryReset/FactoryResetButton';
13
13
  import { CollapsibleGroup } from '../SidePanel/Group';
14
14
  import Spinner from '../Spinner/Spinner';
15
+ import telemetry from '../telemetry/telemetry';
15
16
  import { openUrl } from '../utils/open';
16
17
  import { packageJson } from '../utils/packageJson';
17
18
  import { getAppSpecificStore as store } from '../utils/persistentStore';
18
19
  import { generateSystemReport } from '../utils/systemReport';
19
- import usageData from '../utils/usageData';
20
20
  import bugIcon from './bug.svg';
21
21
 
22
22
  import './error-boundary.scss';
23
23
 
24
- const sendGAEvent = (error: string) => {
25
- if (!usageData.isEnabled()) {
26
- return;
27
- }
28
-
29
- usageData.sendErrorReport(error);
24
+ const sendErrorReport = (error: string) => {
25
+ telemetry.sendErrorReport(error);
30
26
  };
31
27
 
32
28
  interface Props {
@@ -36,7 +32,7 @@ interface Props {
36
32
  devices?: Device[];
37
33
  appName?: string;
38
34
  restoreDefaults?: () => void;
39
- sendUsageData?: (message: string) => void;
35
+ sendTelemetryEvent?: (message: string) => void;
40
36
  }
41
37
 
42
38
  const genericRestoreDefaults = () => {
@@ -65,11 +61,16 @@ class ErrorBoundary extends React.Component<
65
61
  }
66
62
 
67
63
  componentDidCatch(error: Error) {
68
- const { devices, selectedDevice, selectedSerialNumber, sendUsageData } =
69
- this.props;
70
- sendUsageData != null
71
- ? sendUsageData(error.message)
72
- : sendGAEvent(error.message);
64
+ const {
65
+ devices,
66
+ selectedDevice,
67
+ selectedSerialNumber,
68
+ sendTelemetryEvent,
69
+ } = this.props;
70
+
71
+ sendTelemetryEvent != null
72
+ ? sendTelemetryEvent(error.message)
73
+ : sendErrorReport(error.message);
73
74
 
74
75
  generateSystemReport(
75
76
  new Date().toISOString().replace(/:/g, '-'),
@@ -8,14 +8,14 @@
8
8
 
9
9
  .shared-tooltip {
10
10
  div.arrow:first-child {
11
- width: 20px;
12
- height: 20px;
11
+ width: 12px;
12
+ height: 12px;
13
13
  pointer-events: none;
14
14
  }
15
15
 
16
16
  &.bs-tooltip-top {
17
17
  div.arrow:first-child {
18
- bottom: -14px;
18
+ bottom: -6px;
19
19
 
20
20
  &::before {
21
21
  border-top-color: $gray-900;
@@ -26,7 +26,7 @@
26
26
 
27
27
  &.bs-tooltip-right {
28
28
  div.arrow:first-child {
29
- left: -14px;
29
+ left: -6px;
30
30
 
31
31
  &::before {
32
32
  border-right-color: $gray-900;
@@ -37,7 +37,7 @@
37
37
 
38
38
  &.bs-tooltip-bottom {
39
39
  div.arrow:first-child {
40
- top: -14px;
40
+ top: -6px;
41
41
 
42
42
  &::before {
43
43
  border-bottom-color: $gray-900;
@@ -48,7 +48,7 @@
48
48
 
49
49
  &.bs-tooltip-left {
50
50
  div.arrow:first-child {
51
- right: -14px;
51
+ right: -6px;
52
52
 
53
53
  &::before {
54
54
  border-left-color: $gray-900;
@@ -59,7 +59,6 @@
59
59
 
60
60
  .tooltip-inner {
61
61
  background: $gray-900;
62
- padding-top: 14px;
63
62
  min-width: 240px;
64
63
  }
65
64
  }
@@ -39,15 +39,15 @@ export type XTerminalShellParser = ReturnType<
39
39
 
40
40
  export const xTerminalShellParserWrapper = (terminal: Terminal) => ({
41
41
  getTerminalData: () => {
42
- let out = '';
42
+ let result = '';
43
43
  for (let i = 0; i <= terminal.buffer.active.cursorY; i += 1) {
44
44
  const line = terminal.buffer.active.getLine(i);
45
45
  if (typeof line !== 'undefined') {
46
- out += `\r\n${line.translateToString()}`;
46
+ result += `\r\n${line.translateToString()}`;
47
47
  }
48
48
  }
49
49
 
50
- return out.trim();
50
+ return result.trim();
51
51
  },
52
52
  clear: () => terminal.clear(),
53
53
  getLastLine: () => {
package/src/index.ts CHANGED
@@ -77,8 +77,8 @@ export {
77
77
  export { openUrl, openFile } from './utils/open';
78
78
  export { default as systemReport } from './utils/systemReport';
79
79
 
80
- export { default as usageData } from './utils/usageData';
81
- export { type Metadata as UsageDataMetadata } from './utils/usageDataCommon';
80
+ export { default as telemetry } from './telemetry/telemetry';
81
+ export { type default as TelemetryMetadata } from './telemetry/TelemetryMetadata';
82
82
  export { default as classNames } from './utils/classNames';
83
83
  export { truncateMiddle } from './utils/truncateMiddle';
84
84
 
@@ -0,0 +1,9 @@
1
+ /*
2
+ * Copyright (c) 2023 Nordic Semiconductor ASA
3
+ *
4
+ * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause
5
+ */
6
+
7
+ export default interface TelemetryMetadata {
8
+ [key: string]: unknown;
9
+ }
@@ -0,0 +1,80 @@
1
+ /*
2
+ * Copyright (c) 2023 Nordic Semiconductor ASA
3
+ *
4
+ * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause
5
+ */
6
+
7
+ import si from 'systeminformation';
8
+ import { Logger } from 'winston';
9
+
10
+ import {
11
+ deleteHasUserAgreedToTelemetry,
12
+ getHasUserAgreedToTelemetry,
13
+ persistHasUserAgreedToTelemetry,
14
+ } from '../utils/persistentStore';
15
+ import TelemetryMetadata from './TelemetryMetadata';
16
+
17
+ type MaybePromise<T> = T | Promise<T>;
18
+
19
+ export default abstract class TelemetrySender {
20
+ readonly INSTRUMENTATION_KEY = '4b8b1a39-37c7-479e-a684-d4763c7c647c';
21
+
22
+ logger?: Logger;
23
+ setLogger = (logger: Logger) => {
24
+ this.logger = logger;
25
+ };
26
+
27
+ isTelemetryAllowedForCurrentApp = false;
28
+ allowTelemetryForCurrentApp = () => {
29
+ this.isTelemetryAllowedForCurrentApp = true;
30
+ };
31
+
32
+ getIsSendingTelemetry = () =>
33
+ this.isTelemetryAllowedForCurrentApp &&
34
+ getHasUserAgreedToTelemetry() === true;
35
+
36
+ async sendAgreementEvent() {
37
+ this.sendEvent('Telemetry Opt-In');
38
+
39
+ const { platform, arch } = await si.osInfo();
40
+ this.sendEvent('Report OS info', { platform, arch });
41
+ }
42
+
43
+ sendDisagreementEvent() {
44
+ this.sendMinimalEvent('Telemetry Opt-Out');
45
+ }
46
+
47
+ async setUsersAgreedToTelemetry(hasAgreed: boolean) {
48
+ persistHasUserAgreedToTelemetry(hasAgreed);
49
+
50
+ if (hasAgreed) {
51
+ await this.sendAgreementEvent();
52
+ } else {
53
+ this.sendDisagreementEvent();
54
+ }
55
+
56
+ this.logger?.debug(
57
+ `Telemetry has been ${hasAgreed ? 'enabled' : 'disabled'}`
58
+ );
59
+ }
60
+
61
+ setUsersWithdrewTelemetryAgreement() {
62
+ deleteHasUserAgreedToTelemetry();
63
+ this.sendMinimalEvent('Telemetry Opt-Reset');
64
+ this.logger?.debug('Telemetry has been reset');
65
+ }
66
+
67
+ sendMinimalEvent(action: string) {
68
+ this.sendEvent(action, { removeAllMetadata: true });
69
+ }
70
+
71
+ abstract sendEvent(
72
+ action: string,
73
+ metadata?: TelemetryMetadata
74
+ ): MaybePromise<void>;
75
+ abstract sendPageView(pageName: string): MaybePromise<void>;
76
+ abstract sendMetric(name: string, average: number): MaybePromise<void>;
77
+ abstract sendTrace(message: string): MaybePromise<void>;
78
+ abstract sendErrorReport(error: Error): MaybePromise<void>;
79
+ abstract flush(): MaybePromise<void>;
80
+ }
@@ -0,0 +1,80 @@
1
+ /*
2
+ * Copyright (c) 2023 Nordic Semiconductor ASA
3
+ *
4
+ * SPDX-License-Identifier: LicenseRef-Nordic-4-Clause
5
+ */
6
+
7
+ import { TelemetryClient } from 'applicationinsights';
8
+
9
+ import { isDevelopment } from '../utils/environment';
10
+ import { packageJson } from '../utils/packageJson';
11
+ import TelemetryMetadata from './TelemetryMetadata';
12
+ import TelemetrySender from './TelemetrySender';
13
+
14
+ export default class TelemetrySenderInMain extends TelemetrySender {
15
+ client?: TelemetryClient;
16
+
17
+ initClient() {
18
+ const appPackageJson = packageJson();
19
+ const applicationName = appPackageJson.name;
20
+ const applicationVersion = appPackageJson.version;
21
+
22
+ this.client = new TelemetryClient(this.INSTRUMENTATION_KEY);
23
+ this.client.config.enableAutoCollectConsole = false;
24
+ this.client.config.enableAutoCollectDependencies = false;
25
+ this.client.config.enableAutoCollectExceptions = false;
26
+ this.client.config.enableAutoCollectIncomingRequestAzureFunctions =
27
+ false;
28
+ this.client.config.enableAutoCollectHeartbeat = false;
29
+ this.client.config.enableAutoCollectPerformance = false;
30
+ this.client.config.enableAutoCollectPreAggregatedMetrics = false;
31
+ this.client.config.enableAutoCollectRequests = false;
32
+ this.client.config.enableAutoDependencyCorrelation = false;
33
+
34
+ // Add app name and version to every event
35
+ this.client.addTelemetryProcessor(envelope => {
36
+ if (envelope.data.baseData?.properties.removeAllMetadata) {
37
+ envelope.tags = [];
38
+ envelope.data.baseData = {
39
+ name: envelope.data?.baseData.name,
40
+ };
41
+ } else {
42
+ envelope.tags['ai.cloud.roleInstance'] = undefined; // remove PC name
43
+ if (envelope.data.baseData) {
44
+ envelope.data.baseData.properties = {
45
+ applicationName,
46
+ applicationVersion,
47
+ isDevelopment,
48
+ ...envelope.data.baseData.properties,
49
+ };
50
+ }
51
+ }
52
+
53
+ return true;
54
+ });
55
+
56
+ return this.client;
57
+ }
58
+
59
+ getClient = () => this.client ?? this.initClient();
60
+
61
+ sendEvent = (action: string, metadata?: TelemetryMetadata) => {
62
+ this.getClient().trackEvent({ name: action, properties: metadata });
63
+ this.logger?.debug(`Sending event ${JSON.stringify(action)}`);
64
+ };
65
+
66
+ sendPageView = (pageName: string) =>
67
+ this.getClient().trackPageView({ name: pageName });
68
+
69
+ sendMetric = (name: string, value: number) =>
70
+ this.getClient().trackMetric({ name, value });
71
+
72
+ sendTrace = (message: string) => this.getClient().trackTrace({ message });
73
+
74
+ sendErrorReport = (error: Error) => {
75
+ this.getClient().trackException({ exception: error });
76
+ this.logger?.error(error);
77
+ };
78
+
79
+ flush = () => this.getClient().flush();
80
+ }