@nordicsemiconductor/pc-nrfconnect-shared 121.0.0 → 123.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 (174) hide show
  1. package/Changelog.md +85 -0
  2. package/coverage/cobertura-coverage.xml +2276 -1778
  3. package/ipc/launcherConfig.ts +25 -0
  4. package/ipc/openWindow.ts +17 -1
  5. package/ipc/schema/packageJson.ts +26 -22
  6. package/main/index.ts +11 -5
  7. package/mocks/packageJsonMock.ts +1 -1
  8. package/nrfutil/device/__mocks__/device.ts +2 -0
  9. package/nrfutil/device/batch.ts +19 -9
  10. package/nrfutil/device/common.ts +32 -46
  11. package/nrfutil/device/device.ts +2 -0
  12. package/nrfutil/device/deviceInfo.ts +70 -0
  13. package/nrfutil/device/erase.ts +2 -2
  14. package/nrfutil/device/firmwareRead.ts +2 -2
  15. package/nrfutil/device/getCoreInfo.ts +2 -2
  16. package/nrfutil/device/getFwInfo.ts +2 -2
  17. package/nrfutil/device/getProtectionStatus.ts +2 -2
  18. package/nrfutil/device/list.ts +5 -31
  19. package/nrfutil/device/program.ts +4 -4
  20. package/nrfutil/device/recover.ts +2 -2
  21. package/nrfutil/device/reset.ts +2 -2
  22. package/nrfutil/device/setMcuState.ts +2 -5
  23. package/nrfutil/device/setProtectionStatus.ts +2 -2
  24. package/nrfutil/index.ts +1 -1
  25. package/nrfutil/moduleVersion.ts +22 -2
  26. package/nrfutil/sandbox.ts +52 -32
  27. package/nrfutil/sandboxTypes.ts +15 -1
  28. package/package.json +3 -2
  29. package/scripts/check-app-properties.ts +6 -6
  30. package/scripts/esbuild.ts +3 -3
  31. package/scripts/nordic-publish.js +23 -23
  32. package/scripts/nordic-publish.ts +3 -3
  33. package/scripts/release-shared.ts +2 -2
  34. package/src/About/ApplicationCard.tsx +3 -5
  35. package/src/About/DeviceCard.tsx +6 -5
  36. package/src/About/SupportCard.tsx +2 -2
  37. package/src/App/App.test.tsx +7 -0
  38. package/src/App/App.tsx +14 -27
  39. package/src/Device/DeviceSelector/BasicDeviceInfo.tsx +12 -6
  40. package/src/Device/DeviceSelector/DeviceList/AnimatedList.tsx +1 -1
  41. package/src/Device/DeviceSelector/DeviceList/Device.tsx +7 -5
  42. package/src/Device/DeviceSelector/DeviceList/DeviceList.tsx +23 -5
  43. package/src/Device/DeviceSelector/DeviceList/EditDeviceButtons.tsx +7 -6
  44. package/src/Device/DeviceSelector/DeviceList/MoreDeviceInfo.tsx +26 -30
  45. package/src/Device/DeviceSelector/DeviceList/edit-device-buttons.scss +1 -2
  46. package/src/Device/DeviceSelector/DeviceSelector.test.tsx +17 -37
  47. package/src/Device/DeviceSelector/DeviceSelector.tsx +64 -21
  48. package/src/Device/DeviceSelector/Favorite.tsx +10 -10
  49. package/src/Device/DeviceSelector/basic-device-info.scss +0 -12
  50. package/src/Device/deviceInfo/deviceInfo.ts +2 -2
  51. package/src/Device/deviceLister.ts +111 -59
  52. package/src/Device/deviceSetup.ts +30 -13
  53. package/src/Device/deviceSlice.ts +157 -84
  54. package/src/Device/jprogOperations.ts +56 -27
  55. package/src/Device/sdfuOperations.ts +25 -31
  56. package/src/ErrorBoundary/ErrorBoundary.tsx +7 -13
  57. package/src/Feedback/sendFeedback.ts +2 -4
  58. package/src/InlineInput/NumberInlineInput.tsx +1 -1
  59. package/src/InlineInput/NumberInputWithDropdown.tsx +1 -2
  60. package/src/index.ts +4 -0
  61. package/src/logging/sendInitialLogMessages.ts +15 -13
  62. package/src/utils/appDetails.ts +22 -0
  63. package/src/utils/appDirs.ts +4 -4
  64. package/src/utils/launcherConfig.ts +17 -0
  65. package/src/utils/logLibVersions.ts +1 -1
  66. package/src/utils/packageJson.ts +52 -10
  67. package/src/utils/persistentStore.ts +21 -14
  68. package/src/utils/systemReport.ts +4 -6
  69. package/src/utils/usageData.ts +75 -167
  70. package/src/utils/usageDataCommon.ts +59 -0
  71. package/src/utils/usageDataMain.ts +117 -0
  72. package/src/utils/usageDataRenderer.ts +126 -0
  73. package/src/utils/useHotKey.ts +2 -2
  74. package/typings/generated/ipc/launcherConfig.d.ts +14 -0
  75. package/typings/generated/ipc/launcherConfig.d.ts.map +1 -0
  76. package/typings/generated/ipc/openWindow.d.ts +10 -4
  77. package/typings/generated/ipc/openWindow.d.ts.map +1 -1
  78. package/typings/generated/ipc/schema/packageJson.d.ts +34 -52
  79. package/typings/generated/ipc/schema/packageJson.d.ts.map +1 -1
  80. package/typings/generated/main/index.d.ts +8 -2
  81. package/typings/generated/main/index.d.ts.map +1 -1
  82. package/typings/generated/nrfutil/device/__mocks__/device.d.ts +1 -0
  83. package/typings/generated/nrfutil/device/__mocks__/device.d.ts.map +1 -1
  84. package/typings/generated/nrfutil/device/batch.d.ts +3 -2
  85. package/typings/generated/nrfutil/device/batch.d.ts.map +1 -1
  86. package/typings/generated/nrfutil/device/common.d.ts +7 -34
  87. package/typings/generated/nrfutil/device/common.d.ts.map +1 -1
  88. package/typings/generated/nrfutil/device/device.d.ts +14 -13
  89. package/typings/generated/nrfutil/device/device.d.ts.map +1 -1
  90. package/typings/generated/nrfutil/device/deviceInfo.d.ts +40 -0
  91. package/typings/generated/nrfutil/device/deviceInfo.d.ts.map +1 -0
  92. package/typings/generated/nrfutil/device/erase.d.ts +2 -2
  93. package/typings/generated/nrfutil/device/erase.d.ts.map +1 -1
  94. package/typings/generated/nrfutil/device/firmwareRead.d.ts +2 -2
  95. package/typings/generated/nrfutil/device/firmwareRead.d.ts.map +1 -1
  96. package/typings/generated/nrfutil/device/getCoreInfo.d.ts +2 -2
  97. package/typings/generated/nrfutil/device/getCoreInfo.d.ts.map +1 -1
  98. package/typings/generated/nrfutil/device/getFwInfo.d.ts +2 -2
  99. package/typings/generated/nrfutil/device/getFwInfo.d.ts.map +1 -1
  100. package/typings/generated/nrfutil/device/getProtectionStatus.d.ts +2 -2
  101. package/typings/generated/nrfutil/device/getProtectionStatus.d.ts.map +1 -1
  102. package/typings/generated/nrfutil/device/list.d.ts +3 -3
  103. package/typings/generated/nrfutil/device/list.d.ts.map +1 -1
  104. package/typings/generated/nrfutil/device/program.d.ts +2 -2
  105. package/typings/generated/nrfutil/device/program.d.ts.map +1 -1
  106. package/typings/generated/nrfutil/device/recover.d.ts +2 -2
  107. package/typings/generated/nrfutil/device/recover.d.ts.map +1 -1
  108. package/typings/generated/nrfutil/device/reset.d.ts +2 -2
  109. package/typings/generated/nrfutil/device/reset.d.ts.map +1 -1
  110. package/typings/generated/nrfutil/device/setMcuState.d.ts +2 -2
  111. package/typings/generated/nrfutil/device/setMcuState.d.ts.map +1 -1
  112. package/typings/generated/nrfutil/device/setProtectionStatus.d.ts +2 -2
  113. package/typings/generated/nrfutil/device/setProtectionStatus.d.ts.map +1 -1
  114. package/typings/generated/nrfutil/index.d.ts +2 -1
  115. package/typings/generated/nrfutil/index.d.ts.map +1 -1
  116. package/typings/generated/nrfutil/moduleVersion.d.ts +4 -0
  117. package/typings/generated/nrfutil/moduleVersion.d.ts.map +1 -1
  118. package/typings/generated/nrfutil/sandbox.d.ts +2 -2
  119. package/typings/generated/nrfutil/sandbox.d.ts.map +1 -1
  120. package/typings/generated/nrfutil/sandboxTypes.d.ts +10 -1
  121. package/typings/generated/nrfutil/sandboxTypes.d.ts.map +1 -1
  122. package/typings/generated/src/About/ApplicationCard.d.ts.map +1 -1
  123. package/typings/generated/src/About/DeviceCard.d.ts.map +1 -1
  124. package/typings/generated/src/App/App.d.ts +0 -1
  125. package/typings/generated/src/App/App.d.ts.map +1 -1
  126. package/typings/generated/src/Device/DeviceSelector/BasicDeviceInfo.d.ts.map +1 -1
  127. package/typings/generated/src/Device/DeviceSelector/DeviceList/Device.d.ts +0 -1
  128. package/typings/generated/src/Device/DeviceSelector/DeviceList/Device.d.ts.map +1 -1
  129. package/typings/generated/src/Device/DeviceSelector/DeviceList/DeviceList.d.ts.map +1 -1
  130. package/typings/generated/src/Device/DeviceSelector/DeviceList/EditDeviceButtons.d.ts.map +1 -1
  131. package/typings/generated/src/Device/DeviceSelector/DeviceList/MoreDeviceInfo.d.ts +0 -1
  132. package/typings/generated/src/Device/DeviceSelector/DeviceList/MoreDeviceInfo.d.ts.map +1 -1
  133. package/typings/generated/src/Device/DeviceSelector/DeviceSelector.d.ts.map +1 -1
  134. package/typings/generated/src/Device/DeviceSelector/Favorite.d.ts +0 -1
  135. package/typings/generated/src/Device/DeviceSelector/Favorite.d.ts.map +1 -1
  136. package/typings/generated/src/Device/deviceLister.d.ts +1 -15
  137. package/typings/generated/src/Device/deviceLister.d.ts.map +1 -1
  138. package/typings/generated/src/Device/deviceSetup.d.ts +7 -6
  139. package/typings/generated/src/Device/deviceSetup.d.ts.map +1 -1
  140. package/typings/generated/src/Device/deviceSlice.d.ts +16 -15
  141. package/typings/generated/src/Device/deviceSlice.d.ts.map +1 -1
  142. package/typings/generated/src/Device/jprogOperations.d.ts.map +1 -1
  143. package/typings/generated/src/Device/sdfuOperations.d.ts.map +1 -1
  144. package/typings/generated/src/ErrorBoundary/ErrorBoundary.d.ts.map +1 -1
  145. package/typings/generated/src/Feedback/sendFeedback.d.ts.map +1 -1
  146. package/typings/generated/src/InlineInput/NumberInlineInput.d.ts +1 -1
  147. package/typings/generated/src/InlineInput/NumberInlineInput.d.ts.map +1 -1
  148. package/typings/generated/src/InlineInput/NumberInputWithDropdown.d.ts.map +1 -1
  149. package/typings/generated/src/index.d.ts +3 -1
  150. package/typings/generated/src/index.d.ts.map +1 -1
  151. package/typings/generated/src/logging/sendInitialLogMessages.d.ts.map +1 -1
  152. package/typings/generated/src/utils/appDetails.d.ts +4 -0
  153. package/typings/generated/src/utils/appDetails.d.ts.map +1 -0
  154. package/typings/generated/src/utils/appDirs.d.ts +1 -1
  155. package/typings/generated/src/utils/appDirs.d.ts.map +1 -1
  156. package/typings/generated/src/utils/launcherConfig.d.ts +4 -0
  157. package/typings/generated/src/utils/launcherConfig.d.ts.map +1 -0
  158. package/typings/generated/src/utils/packageJson.d.ts +30 -7
  159. package/typings/generated/src/utils/packageJson.d.ts.map +1 -1
  160. package/typings/generated/src/utils/persistentStore.d.ts +3 -2
  161. package/typings/generated/src/utils/persistentStore.d.ts.map +1 -1
  162. package/typings/generated/src/utils/systemReport.d.ts +1 -1
  163. package/typings/generated/src/utils/systemReport.d.ts.map +1 -1
  164. package/typings/generated/src/utils/usageData.d.ts +8 -65
  165. package/typings/generated/src/utils/usageData.d.ts.map +1 -1
  166. package/typings/generated/src/utils/usageDataCommon.d.ts +27 -0
  167. package/typings/generated/src/utils/usageDataCommon.d.ts.map +1 -0
  168. package/typings/generated/src/utils/usageDataMain.d.ts +10 -0
  169. package/typings/generated/src/utils/usageDataMain.d.ts.map +1 -0
  170. package/typings/generated/src/utils/usageDataRenderer.d.ts +10 -0
  171. package/typings/generated/src/utils/usageDataRenderer.d.ts.map +1 -0
  172. package/src/Device/DeviceSelector/DeviceList/device.scss +0 -28
  173. package/src/Device/DeviceSelector/DeviceList/more-device-info.scss +0 -33
  174. package/src/Device/DeviceSelector/favorite.scss +0 -17
@@ -8,7 +8,8 @@ import { createSlice, PayloadAction } from '@reduxjs/toolkit';
8
8
  import type { AutoDetectTypes } from '@serialport/bindings-cpp';
9
9
  import { SerialPortOpenOptions } from 'serialport';
10
10
 
11
- import { NrfutilDevice, SerialPort } from '../../nrfutil/device/common';
11
+ import { DeviceInfo } from '../../nrfutil';
12
+ import { NrfutilDevice } from '../../nrfutil/device/common';
12
13
  import type { RootState } from '../store';
13
14
  import {
14
15
  getPersistedIsFavorite,
@@ -20,65 +21,83 @@ import {
20
21
  } from '../utils/persistentStore';
21
22
 
22
23
  export interface Device extends NrfutilDevice {
23
- serialNumber: string;
24
- boardVersion?: string;
25
24
  nickname?: string;
26
- serialport?: SerialPort;
27
25
  favorite?: boolean;
28
- id: number;
29
26
  persistedSerialPortOptions?: SerialPortOpenOptions<AutoDetectTypes>;
30
27
  }
31
28
 
29
+ export interface DeviceWithSerialNumber extends Device {
30
+ serialNumber: string;
31
+ }
32
+
33
+ export const isDeviceWithSerialNumber = (
34
+ device: Device
35
+ ): device is DeviceWithSerialNumber =>
36
+ !!(device as DeviceWithSerialNumber).serialNumber;
37
+
38
+ const findDeviceItem = (
39
+ devices: Device[],
40
+ id: number,
41
+ serialNumber?: string | null
42
+ ) => {
43
+ const index = devices.findIndex(
44
+ d => d.id === id || d.serialNumber === serialNumber
45
+ );
46
+
47
+ return { index, device: devices[index] };
48
+ };
49
+
32
50
  const updateDevice = (
33
51
  state: DeviceState,
34
- serialNumber: string,
35
- updateToMergeIn: Partial<Device>
52
+ updateToMergeIn: Partial<Device>,
53
+ id: number,
54
+ serialNumber?: string | null
36
55
  ) => {
37
- const device = state.devices.get(serialNumber);
56
+ const device = findDeviceItem(state.devices, id, serialNumber).device;
38
57
  if (device) {
39
58
  Object.assign(device, updateToMergeIn);
40
59
  }
41
60
  };
42
61
 
43
62
  export interface DeviceState {
44
- devices: Map<string, Device>;
45
- deviceInfo: Device | null;
46
- selectedSerialNumber: string | null;
63
+ devices: Device[];
47
64
  readbackProtection: 'unknown' | 'protected' | 'unprotected';
65
+ selectedDevice?: Device;
66
+ selectedDeviceInfo?: DeviceInfo;
48
67
  }
49
68
 
50
69
  const initialState: DeviceState = {
51
- devices: new Map(),
52
- selectedSerialNumber: null,
53
- deviceInfo: null,
70
+ devices: [],
54
71
  readbackProtection: 'unknown',
55
72
  };
56
73
 
57
74
  const setPersistedData = (device: Device) => {
58
- const newDevice = {
59
- ...device,
60
- favorite: getPersistedIsFavorite(device.serialNumber),
61
- nickname: getPersistedNickname(device.serialNumber),
62
- };
63
-
64
- const persistedSerialPortSettings = getPersistedSerialPortSettings(
65
- newDevice.serialNumber
66
- );
67
-
68
- if (persistedSerialPortSettings) {
69
- const path =
70
- newDevice.serialPorts?.[persistedSerialPortSettings.vComIndex]
71
- ?.comName;
72
-
73
- if (path) {
74
- newDevice.persistedSerialPortOptions = {
75
- ...persistedSerialPortSettings.serialPortOptions,
76
- path,
77
- };
75
+ if (device.serialNumber) {
76
+ const newDevice = { ...device };
77
+ newDevice.favorite = getPersistedIsFavorite(device.serialNumber);
78
+ newDevice.nickname = getPersistedNickname(device.serialNumber);
79
+
80
+ const persistedSerialPortSettings = getPersistedSerialPortSettings(
81
+ device.serialNumber
82
+ );
83
+
84
+ if (persistedSerialPortSettings) {
85
+ const path =
86
+ newDevice.serialPorts?.[persistedSerialPortSettings.vComIndex]
87
+ ?.comName;
88
+
89
+ if (path) {
90
+ newDevice.persistedSerialPortOptions = {
91
+ ...persistedSerialPortSettings.serialPortOptions,
92
+ path,
93
+ };
94
+ }
78
95
  }
96
+
97
+ return newDevice;
79
98
  }
80
99
 
81
- return newDevice;
100
+ return device;
82
101
  };
83
102
 
84
103
  const slice = createSlice({
@@ -89,104 +108,158 @@ const slice = createSlice({
89
108
  * Indicates that a device has been selected.
90
109
  */
91
110
  selectDevice: (state, action: PayloadAction<Device>) => {
92
- state.selectedSerialNumber = action.payload.serialNumber;
111
+ state.selectedDevice = action.payload;
112
+ },
113
+
114
+ setSelectedDeviceInfo: (
115
+ state,
116
+ action: PayloadAction<DeviceInfo | undefined>
117
+ ) => {
118
+ state.selectedDeviceInfo = action.payload;
93
119
  },
94
120
 
95
121
  /*
96
122
  * Indicates that the currently selected device has been deselected.
97
123
  */
98
124
  deselectDevice: state => {
99
- state.selectedSerialNumber = null;
100
- state.deviceInfo = null;
125
+ state.selectedDevice = undefined;
126
+ state.selectedDeviceInfo = undefined;
101
127
  state.readbackProtection = 'unknown';
102
128
  },
103
129
 
104
130
  addDevice: (state, action: PayloadAction<Device>) => {
105
- state.devices.set(
106
- action.payload.serialNumber,
107
- setPersistedData(action.payload)
131
+ const index = state.devices.findIndex(
132
+ item =>
133
+ item.serialNumber === action.payload.serialNumber ||
134
+ item.id === action.payload.id
108
135
  );
136
+
137
+ const device = setPersistedData(action.payload);
138
+ if (index !== -1) {
139
+ state.devices[index] = device;
140
+ } else {
141
+ state.devices.push(device);
142
+ }
109
143
  },
110
144
 
111
145
  persistSerialPortOptions: (
112
146
  state,
113
147
  action: PayloadAction<SerialPortOpenOptions<AutoDetectTypes>>
114
148
  ) => {
115
- if (state.selectedSerialNumber === null) return;
149
+ if (!state.selectedDevice) return;
116
150
 
117
- const selectedDevice = state.devices.get(
118
- state.selectedSerialNumber
119
- );
151
+ const selectedDevice = state.selectedDevice;
120
152
 
121
153
  if (selectedDevice) {
122
154
  const vComIndex = selectedDevice.serialPorts?.findIndex(
123
155
  e => e.comName === action.payload.path
124
156
  );
125
157
 
126
- if (vComIndex !== undefined && vComIndex !== -1) {
158
+ if (
159
+ selectedDevice.serialNumber && // we want to disregard comparing devices with no sn
160
+ vComIndex !== undefined &&
161
+ vComIndex !== -1
162
+ ) {
127
163
  // eslint-disable-next-line @typescript-eslint/no-unused-vars -- used to filter out the path property
128
164
  const { path: _, ...serialPortOptions } = action.payload;
129
165
 
130
166
  persistSerialPortSettingsToStore(
131
- state.selectedSerialNumber,
167
+ selectedDevice.serialNumber,
132
168
  {
133
169
  serialPortOptions,
134
170
  vComIndex,
135
171
  }
136
172
  );
137
173
 
138
- state.devices.set(state.selectedSerialNumber, {
139
- ...selectedDevice,
140
- persistedSerialPortOptions: action.payload,
141
- });
174
+ updateDevice(
175
+ state,
176
+ {
177
+ ...selectedDevice,
178
+ persistedSerialPortOptions: action.payload,
179
+ },
180
+ selectedDevice.id,
181
+ selectedDevice.serialNumber
182
+ );
142
183
  }
143
184
  }
144
185
  },
145
186
 
146
187
  removeDevice: (state, action: PayloadAction<Device>) => {
147
- state.devices.delete(action.payload.serialNumber);
148
-
149
- if (state.selectedSerialNumber === action.payload.serialNumber) {
150
- state.selectedSerialNumber = null;
151
- state.deviceInfo = null;
188
+ const index = findDeviceItem(
189
+ state.devices,
190
+ action.payload.id,
191
+ action.payload.serialNumber
192
+ ).index;
193
+ state.devices.splice(index, 1);
194
+
195
+ if (action.payload.id === state.selectedDevice?.id) {
196
+ state.selectedDevice = undefined;
197
+ state.selectedDeviceInfo = undefined;
152
198
  }
153
199
  },
154
200
 
155
- toggleDeviceFavorited: (state, action: PayloadAction<string>) => {
156
- const newFavoriteState = !state.devices.get(action.payload)
157
- ?.favorite;
158
- persistIsFavorite(action.payload, newFavoriteState);
159
- updateDevice(state, action.payload, {
160
- favorite: newFavoriteState,
161
- });
201
+ toggleDeviceFavorited: (state, action: PayloadAction<Device>) => {
202
+ const device = findDeviceItem(
203
+ state.devices,
204
+ action.payload.id,
205
+ action.payload.serialNumber
206
+ ).device;
207
+
208
+ if (!device.serialNumber) return;
209
+
210
+ const newFavoriteState = !device.favorite;
211
+
212
+ persistIsFavorite(device.serialNumber, newFavoriteState);
213
+ updateDevice(
214
+ state,
215
+ {
216
+ favorite: newFavoriteState,
217
+ },
218
+ action.payload.id,
219
+ action.payload.serialNumber
220
+ );
162
221
  },
163
222
 
164
223
  setDeviceNickname: {
165
- prepare: (serialNumber: string, nickname: string) => ({
166
- payload: { serialNumber, nickname },
224
+ prepare: (device: Device, nickname: string) => ({
225
+ payload: { device, nickname },
167
226
  }),
168
227
  reducer: (
169
228
  state,
170
229
  action: PayloadAction<{
171
- serialNumber: string;
230
+ device: Device;
172
231
  nickname: string;
173
232
  }>
174
233
  ) => {
234
+ if (!action.payload.device.serialNumber) return;
235
+
175
236
  persistNickname(
176
- action.payload.serialNumber,
237
+ action.payload.device.serialNumber,
177
238
  action.payload.nickname
178
239
  );
179
- updateDevice(state, action.payload.serialNumber, {
180
- nickname: action.payload.nickname,
181
- });
240
+ updateDevice(
241
+ state,
242
+ {
243
+ nickname: action.payload.nickname,
244
+ },
245
+ action.payload.device.id,
246
+ action.payload.device.serialNumber
247
+ );
182
248
  },
183
249
  },
184
250
 
185
- resetDeviceNickname: (state, action: PayloadAction<string>) => {
186
- persistNickname(action.payload, '');
187
- updateDevice(state, action.payload, {
188
- nickname: '',
189
- });
251
+ resetDeviceNickname: (state, action: PayloadAction<Device>) => {
252
+ if (!action.payload.serialNumber) return;
253
+
254
+ persistNickname(action.payload.serialNumber, '');
255
+ updateDevice(
256
+ state,
257
+ {
258
+ nickname: '',
259
+ },
260
+ action.payload.id,
261
+ action.payload.serialNumber
262
+ );
190
263
  },
191
264
 
192
265
  setReadbackProtected: (
@@ -204,6 +277,7 @@ export const {
204
277
  deselectDevice,
205
278
  resetDeviceNickname,
206
279
  selectDevice,
280
+ setSelectedDeviceInfo,
207
281
  addDevice,
208
282
  removeDevice,
209
283
  setDeviceNickname,
@@ -213,22 +287,21 @@ export const {
213
287
  },
214
288
  } = slice;
215
289
 
216
- export const getDevice = (serialNumber: string) => (state: RootState) =>
217
- state.device.devices.get(serialNumber);
290
+ export const getDevice = (state: RootState, serialNumber: string) =>
291
+ state.device.devices.find(d => d.serialNumber === serialNumber);
218
292
 
219
293
  export const getDevices = (state: RootState) => state.device.devices;
220
294
 
221
295
  export const deviceIsSelected = (state: RootState) =>
222
- state.device.selectedSerialNumber != null;
296
+ !!state.device.selectedDevice;
297
+
298
+ export const selectedDevice = (state: RootState) => state.device.selectedDevice;
223
299
 
224
- export const selectedDevice = (state: RootState) =>
225
- state.device.selectedSerialNumber !== null
226
- ? state.device.devices.get(state.device.selectedSerialNumber)
227
- : undefined;
300
+ export const selectedDeviceInfo = (state: RootState) =>
301
+ state.device.selectedDevice ? state.device.selectedDeviceInfo : undefined;
228
302
 
229
- export const deviceInfo = (state: RootState) => state.device.deviceInfo;
230
303
  export const selectedSerialNumber = (state: RootState) =>
231
- state.device.selectedSerialNumber;
304
+ state.device.selectedDevice?.serialNumber;
232
305
 
233
306
  export const getReadbackProtection = (state: RootState) =>
234
307
  state.device.readbackProtection;
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import NrfutilDeviceLib from '../../nrfutil/device/device';
8
+ import { DeviceInfo } from '../../nrfutil/device/deviceInfo';
8
9
  import { FWInfo } from '../../nrfutil/device/getFwInfo';
9
10
  import logger from '../logging';
10
11
  import type { AppThunk, RootState } from '../store';
@@ -18,14 +19,15 @@ const getDeviceReadProtection = async (
18
19
  readbackProtection: 'unknown' | 'protected' | 'unprotected';
19
20
  }> => {
20
21
  try {
22
+ logger.info('Checking readback protection on device');
21
23
  const info = await NrfutilDeviceLib.getFwInfo(device);
22
24
  return {
23
25
  fwInfo: info,
24
26
  readbackProtection: 'unprotected',
25
27
  };
26
- } catch (error) {
27
- // @ts-expect-error Wrongly typed in device lib at the moment
28
- if (error.error_code === 24) {
28
+ } catch (e) {
29
+ const error = e as Error;
30
+ if (error.message.includes('NotAvailableBecauseProtection')) {
29
31
  logger.warn(
30
32
  'Readback protection on device enabled. Unable to verify that the firmware version is correct.'
31
33
  );
@@ -49,29 +51,50 @@ const programDeviceWithFw =
49
51
  ): AppThunk<RootState, Promise<Device>> =>
50
52
  async (dispatch, getState) => {
51
53
  try {
52
- if (getState().device.readbackProtection === 'protected') {
53
- logger.info('Recovering device');
54
- onProgress(0, 'Recovering device');
55
- await NrfutilDeviceLib.recover(device, 'Application');
54
+ const batch = NrfutilDeviceLib.batch();
55
+ if (getState().device.readbackProtection !== 'unprotected') {
56
+ batch.recover('Application', {
57
+ onTaskBegin: () =>
58
+ logger.info(`Device protected, recovering device`),
59
+ onTaskEnd: () => logger.info(`Finished recovering device.`),
60
+ onException: () =>
61
+ logger.error(`Failed to recover device.`),
62
+ onProgress: progress => {
63
+ onProgress(
64
+ progress.totalProgressPercentage,
65
+ 'Recovering device'
66
+ );
67
+ },
68
+ });
56
69
  }
57
70
 
58
- logger.debug(
59
- `Programming ${device.serialNumber} with ${selectedFw.fw}`
60
- );
61
- await NrfutilDeviceLib.program(
62
- device,
63
- selectedFw.fw,
64
- progress => {
71
+ batch.program(selectedFw.fw, 'Application', undefined, undefined, {
72
+ onTaskBegin: () => logger.info(`Programming device`),
73
+ onTaskEnd: () => logger.info(`Finished programming device.`),
74
+ onException: () => logger.error(`Failed to program device.`),
75
+ onProgress: progress => {
65
76
  onProgress(
66
77
  progress.totalProgressPercentage,
67
78
  progress.message ?? 'programming'
68
79
  );
69
80
  },
70
- 'Application'
71
- );
72
- logger.debug(`Resetting ${device.serialNumber}`);
73
- onProgress(100, 'Resetting device');
81
+ });
82
+
83
+ batch.reset('Application', undefined, {
84
+ onTaskBegin: () => logger.info(`Resting device`),
85
+ onTaskEnd: () => logger.info(`Finished resting device.`),
86
+ onException: () => logger.error(`Failed to reset device.`),
87
+ onProgress: progress => {
88
+ onProgress(
89
+ progress.totalProgressPercentage,
90
+ 'Resetting device'
91
+ );
92
+ },
93
+ });
94
+
95
+ await batch.run(device);
74
96
  await NrfutilDeviceLib.reset(device);
97
+ onProgress(0, 'Updating readback protection');
75
98
  const { readbackProtection } = await getDeviceReadProtection(
76
99
  device
77
100
  );
@@ -88,12 +111,18 @@ const programDeviceWithFw =
88
111
  return device;
89
112
  };
90
113
 
91
- const firmwareOptions = (device: Device, firmware: JprogEntry[]) =>
114
+ const firmwareOptions = (
115
+ device: Device,
116
+ firmware: JprogEntry[],
117
+ deviceInfo?: DeviceInfo
118
+ ) =>
92
119
  firmware.filter(fw => {
93
- const family = (device.jlink?.deviceFamily || '').toLowerCase();
94
- const deviceType = (device.jlink?.deviceVersion || '').toLowerCase();
120
+ const family = (device.devkit?.deviceFamily || '').toLowerCase();
121
+ const deviceType = (
122
+ deviceInfo?.jlink?.deviceVersion || ''
123
+ ).toLowerCase();
95
124
  const shortDeviceType = deviceType.split('_').shift();
96
- const boardVersion = (device.jlink?.boardVersion || '').toLowerCase();
125
+ const boardVersion = (device.devkit?.boardVersion || '').toLowerCase();
97
126
 
98
127
  const key = fw.key.toLowerCase();
99
128
  return (
@@ -108,11 +137,11 @@ export const jprogDeviceSetup = (
108
137
  firmware: JprogEntry[],
109
138
  needSerialport = false
110
139
  ): DeviceSetup => ({
111
- supportsProgrammingMode: (device: Device) =>
140
+ supportsProgrammingMode: device =>
112
141
  (needSerialport === !!device.traits.serialPorts || !needSerialport) &&
113
142
  !!device.traits.jlink,
114
- getFirmwareOptions: device =>
115
- firmwareOptions(device, firmware).map(firmwareOption => ({
143
+ getFirmwareOptions: (device, deviceInfo) =>
144
+ firmwareOptions(device, firmware, deviceInfo).map(firmwareOption => ({
116
145
  key: firmwareOption.key,
117
146
  description: firmwareOption.description,
118
147
  programDevice: onProgress => dispatch =>
@@ -120,8 +149,8 @@ export const jprogDeviceSetup = (
120
149
  programDeviceWithFw(device, firmwareOption, onProgress)
121
150
  ),
122
151
  })),
123
- isExpectedFirmware: (device: Device) => dispatch => {
124
- const fwVersions = firmwareOptions(device, firmware);
152
+ isExpectedFirmware: (device, deviceInfo) => dispatch => {
153
+ const fwVersions = firmwareOptions(device, firmware, deviceInfo);
125
154
  if (fwVersions.length === 0) {
126
155
  return Promise.resolve({
127
156
  device,
@@ -46,8 +46,9 @@ export const isDeviceInDFUBootloader = (device: Device) => {
46
46
  d.idProduct === NORDIC_DFU_PRODUCT_ID
47
47
  );
48
48
  }
49
- if (device.serialport) {
50
- const { vendorId, productId } = device.serialport;
49
+
50
+ if (device.serialPorts && device.serialPorts[0]) {
51
+ const { vendorId, productId } = device.serialPorts[0];
51
52
  return vendorId === '1915' && productId?.toUpperCase() === '521F';
52
53
  }
53
54
  return false;
@@ -410,9 +411,7 @@ const programInDFUBootloader =
410
411
  onFail: (reason?: unknown) => void
411
412
  ): AppThunk<RootState, Promise<void>> =>
412
413
  async dispatch => {
413
- logger.debug(
414
- `${device.serialNumber} on ${device.serialport?.comName} is now in DFU-Bootloader...`
415
- );
414
+ logger.debug(`${device.serialNumber} on is now in DFU-Bootloader...`);
416
415
  const { application, softdevice } = dfu;
417
416
  const params: Partial<InitPacket> = dfu.params || {};
418
417
 
@@ -545,9 +544,9 @@ export const sdfuDeviceSetup = (
545
544
  dfuFirmware: DfuEntry[],
546
545
  needSerialport = false
547
546
  ): DeviceSetup => ({
548
- supportsProgrammingMode: (device: Device) =>
549
- ((!!device.dfuTriggerVersion &&
550
- device.dfuTriggerVersion.semVer.length > 0) ||
547
+ supportsProgrammingMode: (device, deviceInfo) =>
548
+ ((!!deviceInfo?.dfuTriggerVersion &&
549
+ deviceInfo.dfuTriggerVersion.semVer.length > 0) ||
551
550
  isDeviceInDFUBootloader(device)) &&
552
551
  (needSerialport === device.traits.serialPorts || !needSerialport),
553
552
  getFirmwareOptions: device =>
@@ -559,31 +558,26 @@ export const sdfuDeviceSetup = (
559
558
  programDeviceWithFw(device, firmwareOption, onProgress)
560
559
  ),
561
560
  })),
562
- isExpectedFirmware: (device: Device) => () =>
563
- new Promise<{
564
- device: Device;
565
- validFirmware: boolean;
566
- }>(resolve => {
567
- if (device.dfuTriggerVersion) {
568
- logger.debug(
569
- 'Device has DFU trigger interface, the device is in Application mode'
570
- );
561
+ isExpectedFirmware: (device, deviceInfo) => () => {
562
+ if (deviceInfo?.dfuTriggerVersion) {
563
+ logger.debug(
564
+ 'Device has DFU trigger interface, the device is in Application mode'
565
+ );
571
566
 
572
- const { semVer } = device.dfuTriggerVersion;
567
+ const { semVer } = deviceInfo.dfuTriggerVersion;
573
568
 
574
- resolve({
575
- device,
576
- validFirmware:
577
- dfuFirmware.filter(fw => fw.semver === semVer).length >
578
- 0,
579
- });
580
- } else {
581
- resolve({
582
- device,
583
- validFirmware: false,
584
- });
585
- }
586
- }),
569
+ return Promise.resolve({
570
+ device,
571
+ validFirmware:
572
+ dfuFirmware.filter(fw => fw.semver === semVer).length > 0,
573
+ });
574
+ }
575
+
576
+ return Promise.resolve({
577
+ device,
578
+ validFirmware: false,
579
+ });
580
+ },
587
581
  tryToSwitchToApplicationMode: device => dispatch =>
588
582
  new Promise<Device>((resolve, reject) => {
589
583
  dispatch(switchToApplicationMode(device, resolve, reject));
@@ -13,27 +13,20 @@ import FactoryResetButton from '../FactoryReset/FactoryResetButton';
13
13
  import { CollapsibleGroup } from '../SidePanel/Group';
14
14
  import Spinner from '../Spinner/Spinner';
15
15
  import { openUrl } from '../utils/open';
16
- import packageJson from '../utils/packageJson';
16
+ import { packageJson } from '../utils/packageJson';
17
17
  import { getAppSpecificStore as store } from '../utils/persistentStore';
18
18
  import { generateSystemReport } from '../utils/systemReport';
19
- import {
20
- init as initGA,
21
- isEnabled,
22
- isInitialized as isGAInitialized,
23
- sendErrorReport,
24
- } from '../utils/usageData';
19
+ import usageData from '../utils/usageData';
25
20
  import bugIcon from './bug.svg';
26
21
 
27
22
  import './error-boundary.scss';
28
23
 
29
24
  const sendGAEvent = (error: string) => {
30
- if (!isEnabled()) {
25
+ if (!usageData.isEnabled()) {
31
26
  return;
32
27
  }
33
- if (!isGAInitialized()) {
34
- initGA(packageJson());
35
- }
36
- sendErrorReport(error);
28
+
29
+ usageData.sendErrorReport(error);
37
30
  };
38
31
 
39
32
  interface Props {
@@ -97,7 +90,8 @@ class ErrorBoundary extends React.Component<
97
90
  return children;
98
91
  }
99
92
 
100
- const appDisplayName = appName || packageJson().displayName;
93
+ const appDisplayName =
94
+ appName || packageJson().displayName || packageJson().name;
101
95
 
102
96
  return (
103
97
  <div className="error-boundary__container">
@@ -5,18 +5,16 @@
5
5
  */
6
6
 
7
7
  import { isDevelopment } from '../utils/environment';
8
- import packageJson from '../utils/packageJson';
8
+ import { packageJson } from '../utils/packageJson';
9
9
 
10
10
  const formURL =
11
11
  isDevelopment === true
12
12
  ? 'https://formkeep.com/f/87deb409a565'
13
13
  : 'https://formkeep.com/f/36b394b92851';
14
14
 
15
- const getAppName = () => packageJson().name;
16
-
17
15
  export default async (feedback: string, category?: string) => {
18
16
  const data: Record<string, unknown> = {
19
- name: getAppName(),
17
+ name: packageJson().name,
20
18
  feedback,
21
19
  platform: process.platform,
22
20
  };
@@ -19,7 +19,7 @@ import InlineInput from './InlineInput';
19
19
 
20
20
  import './number-inline-input.scss';
21
21
 
22
- export interface NumberInlineInput {
22
+ interface NumberInlineInput {
23
23
  disabled?: boolean;
24
24
  value: number;
25
25
  range: RangeOrValues;