@nordicsemiconductor/pc-nrfconnect-shared 173.0.0 → 175.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.
- package/Changelog.md +32 -3
- package/ipc/MetaFiles.ts +1 -0
- package/ipc/apps.ts +1 -0
- package/package.json +3 -3
- package/scripts/nordic-publish.js +20 -20
- package/scripts/nordic-publish.ts +17 -50
- package/src/App/App.tsx +17 -13
- package/src/App/appLayout.ts +95 -23
- package/src/NavBar/NavMenu.test.tsx +64 -1
- package/src/NavBar/NavMenu.tsx +7 -7
- package/src/NavBar/NavMenuItem.tsx +4 -3
- package/src/index.ts +6 -1
- package/src/utils/persistentStore.ts +6 -4
- package/typings/generated/ipc/MetaFiles.d.ts +1 -0
- package/typings/generated/ipc/MetaFiles.d.ts.map +1 -1
- package/typings/generated/ipc/apps.d.ts +1 -0
- package/typings/generated/ipc/apps.d.ts.map +1 -1
- package/typings/generated/src/App/App.d.ts +2 -0
- package/typings/generated/src/App/App.d.ts.map +1 -1
- package/typings/generated/src/App/appLayout.d.ts +19 -5
- package/typings/generated/src/App/appLayout.d.ts.map +1 -1
- package/typings/generated/src/NavBar/NavMenuItem.d.ts +1 -1
- package/typings/generated/src/NavBar/NavMenuItem.d.ts.map +1 -1
- package/typings/generated/src/index.d.ts +1 -1
- package/typings/generated/src/index.d.ts.map +1 -1
- package/typings/generated/src/utils/persistentStore.d.ts +4 -3
- package/typings/generated/src/utils/persistentStore.d.ts.map +1 -1
|
@@ -24,6 +24,7 @@ interface LegacyAppInfo {
|
|
|
24
24
|
versions?: {
|
|
25
25
|
[version: string]: {
|
|
26
26
|
dist: {
|
|
27
|
+
publishTimestamp?: string;
|
|
27
28
|
tarball: string;
|
|
28
29
|
shasum: string;
|
|
29
30
|
};
|
|
@@ -233,48 +234,19 @@ const downloadFileContent = (filename: string) =>
|
|
|
233
234
|
});
|
|
234
235
|
});
|
|
235
236
|
|
|
236
|
-
const
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
console.log(
|
|
242
|
-
`App info file will be created from scratch due to: ${errorAsString(
|
|
243
|
-
error
|
|
244
|
-
)}`
|
|
245
|
-
);
|
|
246
|
-
return {};
|
|
247
|
-
}
|
|
248
|
-
};
|
|
237
|
+
const assertAppVersionIsValid = (
|
|
238
|
+
latestAppVersion: string | undefined,
|
|
239
|
+
app: App
|
|
240
|
+
) => {
|
|
241
|
+
if (latestAppVersion != null) {
|
|
242
|
+
console.log(`Latest published version ${latestAppVersion}`);
|
|
249
243
|
|
|
250
|
-
|
|
251
|
-
const latest = appInfo['dist-tags']?.latest;
|
|
252
|
-
if (latest != null) {
|
|
253
|
-
console.log(`Latest published version ${latest}`);
|
|
254
|
-
|
|
255
|
-
if (semver.lte(app.version, latest) && app.isOfficial) {
|
|
244
|
+
if (semver.lte(app.version, latestAppVersion) && app.isOfficial) {
|
|
256
245
|
throw new Error(
|
|
257
246
|
'Current package version cannot be published, bump it higher'
|
|
258
247
|
);
|
|
259
248
|
}
|
|
260
249
|
}
|
|
261
|
-
|
|
262
|
-
return {
|
|
263
|
-
...appInfo,
|
|
264
|
-
'dist-tags': {
|
|
265
|
-
...appInfo['dist-tags'],
|
|
266
|
-
latest: app.version,
|
|
267
|
-
},
|
|
268
|
-
versions: {
|
|
269
|
-
...appInfo.versions,
|
|
270
|
-
[app.version]: {
|
|
271
|
-
dist: {
|
|
272
|
-
tarball: `${app.sourceUrl}/${app.filename}`,
|
|
273
|
-
shasum: app.shasum,
|
|
274
|
-
},
|
|
275
|
-
},
|
|
276
|
-
},
|
|
277
|
-
};
|
|
278
250
|
};
|
|
279
251
|
|
|
280
252
|
type UploadLocalFile = (localFileName: string, remote: string) => Promise<void>;
|
|
@@ -289,11 +261,6 @@ const uploadFile: UploadLocalFile & UploadBufferContent = (
|
|
|
289
261
|
client.put(local, remote, err => (err ? reject(err) : resolve()));
|
|
290
262
|
});
|
|
291
263
|
|
|
292
|
-
const getUpdatedLegacyAppInfo = async (app: App) => {
|
|
293
|
-
const appInfo = await downloadLegacyAppInfo(app.name);
|
|
294
|
-
return updateLegacyAppInfo(appInfo, app);
|
|
295
|
-
};
|
|
296
|
-
|
|
297
264
|
const createBlankSourceJson = async (name: string) => {
|
|
298
265
|
try {
|
|
299
266
|
await downloadFileContent('source.json');
|
|
@@ -357,10 +324,12 @@ const getUpdatedSourceJson = async (
|
|
|
357
324
|
};
|
|
358
325
|
};
|
|
359
326
|
|
|
360
|
-
const
|
|
327
|
+
const downloadExistingAppInfo = async (
|
|
328
|
+
app: App
|
|
329
|
+
): Promise<Partial<Pick<AppInfo, 'latestVersion' | 'versions'>>> => {
|
|
361
330
|
try {
|
|
362
331
|
const appInfoContent = await downloadFileContent(app.appInfoName);
|
|
363
|
-
return
|
|
332
|
+
return JSON.parse(appInfoContent) as AppInfo;
|
|
364
333
|
} catch (error) {
|
|
365
334
|
console.log(
|
|
366
335
|
`No previous app versions found due to: ${errorAsString(error)}`
|
|
@@ -377,7 +346,9 @@ const failBecauseOfMissingProperty = () => {
|
|
|
377
346
|
};
|
|
378
347
|
|
|
379
348
|
const getUpdatedAppInfo = async (app: App): Promise<AppInfo> => {
|
|
380
|
-
const
|
|
349
|
+
const oldAppInfo = await downloadExistingAppInfo(app);
|
|
350
|
+
|
|
351
|
+
assertAppVersionIsValid(oldAppInfo.latestVersion, app);
|
|
381
352
|
|
|
382
353
|
const {
|
|
383
354
|
name,
|
|
@@ -399,9 +370,10 @@ const getUpdatedAppInfo = async (app: App): Promise<AppInfo> => {
|
|
|
399
370
|
releaseNotesUrl: `${app.sourceUrl}/${app.releaseNotesFilename}`,
|
|
400
371
|
latestVersion: version,
|
|
401
372
|
versions: {
|
|
402
|
-
...versions,
|
|
373
|
+
...oldAppInfo.versions,
|
|
403
374
|
[version]: {
|
|
404
375
|
tarballUrl: `${app.sourceUrl}/${app.filename}`,
|
|
376
|
+
publishTimestamp: new Date().toISOString(),
|
|
405
377
|
shasum: app.shasum,
|
|
406
378
|
nrfutilModules,
|
|
407
379
|
},
|
|
@@ -409,9 +381,6 @@ const getUpdatedAppInfo = async (app: App): Promise<AppInfo> => {
|
|
|
409
381
|
};
|
|
410
382
|
};
|
|
411
383
|
|
|
412
|
-
const uploadLegacyAppInfo = (app: App, appInfo: LegacyAppInfo) =>
|
|
413
|
-
uploadFile(Buffer.from(JSON.stringify(appInfo, undefined, 2)), app.name);
|
|
414
|
-
|
|
415
384
|
const uploadSourceJson = (sourceJson: SourceJson) =>
|
|
416
385
|
uploadFile(
|
|
417
386
|
Buffer.from(JSON.stringify(sourceJson, undefined, 2)),
|
|
@@ -472,14 +441,12 @@ const main = async () => {
|
|
|
472
441
|
}
|
|
473
442
|
await changeWorkingDirectory(options.sourceDir);
|
|
474
443
|
|
|
475
|
-
const legacyAppInfo = await getUpdatedLegacyAppInfo(app);
|
|
476
444
|
const sourceJson = await getUpdatedSourceJson(app, options);
|
|
477
445
|
const appInfo = await getUpdatedAppInfo(app);
|
|
478
446
|
|
|
479
447
|
await uploadChangelog(app);
|
|
480
448
|
await uploadIcon(app);
|
|
481
449
|
await uploadPackage(app);
|
|
482
|
-
await uploadLegacyAppInfo(app, legacyAppInfo);
|
|
483
450
|
await uploadAppInfo(app, appInfo);
|
|
484
451
|
await uploadSourceJson(sourceJson);
|
|
485
452
|
|
package/src/App/App.tsx
CHANGED
|
@@ -37,6 +37,7 @@ import {
|
|
|
37
37
|
} from '../utils/persistentStore';
|
|
38
38
|
import useHotKey from '../utils/useHotKey';
|
|
39
39
|
import {
|
|
40
|
+
AboutPaneName,
|
|
40
41
|
currentPane as currentPaneSelector,
|
|
41
42
|
isLogVisible as isLogVisibleSelector,
|
|
42
43
|
isSidePanelVisible as isSidePanelVisibleSelector,
|
|
@@ -57,6 +58,8 @@ export interface PaneProps {
|
|
|
57
58
|
|
|
58
59
|
export interface Pane {
|
|
59
60
|
name: string;
|
|
61
|
+
preHidden?: boolean;
|
|
62
|
+
preDisabled?: boolean;
|
|
60
63
|
Main: FC<PaneProps>;
|
|
61
64
|
SidePanel?: FC;
|
|
62
65
|
}
|
|
@@ -95,7 +98,7 @@ const ConnectedApp: FC<ConnectedAppProps> = ({
|
|
|
95
98
|
const isLogVisible = useSelector(isLogVisibleSelector);
|
|
96
99
|
const currentPane = useSelector(currentPaneSelector);
|
|
97
100
|
const allPanes = useAllPanes(panes, documentation, feedbackCategories);
|
|
98
|
-
const
|
|
101
|
+
const currentPaneIndex = allPanes.findIndex(p => p.name === currentPane);
|
|
99
102
|
const dispatch = useDispatch();
|
|
100
103
|
|
|
101
104
|
useHotKey({
|
|
@@ -106,11 +109,9 @@ const ConnectedApp: FC<ConnectedAppProps> = ({
|
|
|
106
109
|
});
|
|
107
110
|
|
|
108
111
|
useEffect(() => {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
useEffect(() => {
|
|
113
|
-
telemetry.sendPageView(paneName.current[currentPane]);
|
|
112
|
+
if (currentPane) {
|
|
113
|
+
telemetry.sendPageView(currentPane);
|
|
114
|
+
}
|
|
114
115
|
}, [currentPane]);
|
|
115
116
|
|
|
116
117
|
useEffect(() => {
|
|
@@ -130,7 +131,8 @@ const ConnectedApp: FC<ConnectedAppProps> = ({
|
|
|
130
131
|
}
|
|
131
132
|
}, [dispatch, showLogByDefault]);
|
|
132
133
|
|
|
133
|
-
const SidePanelComponent =
|
|
134
|
+
const SidePanelComponent =
|
|
135
|
+
currentPaneIndex >= 0 ? allPanes[currentPaneIndex].SidePanel : null;
|
|
134
136
|
const currentSidePanel =
|
|
135
137
|
SidePanelComponent != null ? <SidePanelComponent /> : sidePanel;
|
|
136
138
|
|
|
@@ -152,7 +154,7 @@ const ConnectedApp: FC<ConnectedAppProps> = ({
|
|
|
152
154
|
<div className="core19-main-and-log">
|
|
153
155
|
<Carousel
|
|
154
156
|
className="core19-main-container"
|
|
155
|
-
activeIndex={
|
|
157
|
+
activeIndex={currentPaneIndex}
|
|
156
158
|
controls={false}
|
|
157
159
|
indicators={false}
|
|
158
160
|
keyboard={false}
|
|
@@ -160,9 +162,9 @@ const ConnectedApp: FC<ConnectedAppProps> = ({
|
|
|
160
162
|
slide
|
|
161
163
|
fade
|
|
162
164
|
>
|
|
163
|
-
{allPanes.map(({ name, Main }
|
|
165
|
+
{allPanes.map(({ name, Main }) => (
|
|
164
166
|
<Carousel.Item key={name}>
|
|
165
|
-
<Main active={
|
|
167
|
+
<Main active={name === currentPane} />
|
|
166
168
|
</Carousel.Item>
|
|
167
169
|
))}
|
|
168
170
|
</Carousel>
|
|
@@ -217,8 +219,10 @@ export default ({
|
|
|
217
219
|
const usePersistedPane = () => {
|
|
218
220
|
const dispatch = useDispatch();
|
|
219
221
|
useEffect(() => {
|
|
220
|
-
const pane = getPersistedCurrentPane()
|
|
221
|
-
|
|
222
|
+
const pane = getPersistedCurrentPane();
|
|
223
|
+
if (pane) {
|
|
224
|
+
dispatch(setCurrentPane(pane));
|
|
225
|
+
}
|
|
222
226
|
}, [dispatch]);
|
|
223
227
|
};
|
|
224
228
|
|
|
@@ -233,7 +237,7 @@ const useAllPanes = (
|
|
|
233
237
|
const newPanes = [...panes];
|
|
234
238
|
|
|
235
239
|
newPanes.push({
|
|
236
|
-
name:
|
|
240
|
+
name: AboutPaneName,
|
|
237
241
|
Main: props => (
|
|
238
242
|
<About
|
|
239
243
|
documentation={documentation}
|
package/src/App/appLayout.ts
CHANGED
|
@@ -13,31 +13,43 @@ import {
|
|
|
13
13
|
persistLogVisible,
|
|
14
14
|
} from '../utils/persistentStore';
|
|
15
15
|
|
|
16
|
+
interface Pane {
|
|
17
|
+
name: string;
|
|
18
|
+
hidden: boolean;
|
|
19
|
+
disabled: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
16
22
|
export interface AppLayout {
|
|
17
23
|
isSidePanelVisible: boolean;
|
|
18
24
|
isLogVisible: boolean;
|
|
19
|
-
currentPane
|
|
20
|
-
|
|
25
|
+
currentPane?: string;
|
|
26
|
+
panes: Pane[];
|
|
21
27
|
}
|
|
22
28
|
|
|
23
29
|
const initialState: AppLayout = {
|
|
24
30
|
isSidePanelVisible: true,
|
|
25
31
|
isLogVisible: !!getPersistedLogVisible(),
|
|
26
|
-
currentPane:
|
|
27
|
-
|
|
32
|
+
currentPane: undefined,
|
|
33
|
+
panes: [],
|
|
28
34
|
};
|
|
29
35
|
|
|
30
|
-
const
|
|
36
|
+
export const AboutPaneName = 'About';
|
|
37
|
+
const isAboutPane = (pane: string) => pane === AboutPaneName;
|
|
31
38
|
|
|
32
|
-
const setCurrentPaneInState = (newPane:
|
|
33
|
-
if (!isAboutPane(newPane
|
|
39
|
+
const setCurrentPaneInState = (newPane: string, state: AppLayout) => {
|
|
40
|
+
if (!isAboutPane(newPane)) {
|
|
34
41
|
persistCurrentPane(newPane);
|
|
35
42
|
}
|
|
36
43
|
state.currentPane = newPane;
|
|
37
44
|
};
|
|
38
45
|
|
|
46
|
+
const getValidPanes = (panes: Pane[]) =>
|
|
47
|
+
panes.filter(p => !p.disabled && !p.hidden);
|
|
48
|
+
|
|
39
49
|
interface PaneSpec {
|
|
40
50
|
name: string;
|
|
51
|
+
preHidden?: boolean;
|
|
52
|
+
preDisabled?: boolean;
|
|
41
53
|
}
|
|
42
54
|
|
|
43
55
|
const slice = createSlice({
|
|
@@ -51,27 +63,87 @@ const slice = createSlice({
|
|
|
51
63
|
toggleSidePanelVisible: state => {
|
|
52
64
|
state.isSidePanelVisible = !state.isSidePanelVisible;
|
|
53
65
|
},
|
|
54
|
-
setCurrentPane: (
|
|
55
|
-
state
|
|
56
|
-
{ payload: newPane }: PayloadAction<number>
|
|
57
|
-
) => {
|
|
58
|
-
setCurrentPaneInState(newPane, state);
|
|
66
|
+
setCurrentPane: (state, action: PayloadAction<string>) => {
|
|
67
|
+
setCurrentPaneInState(action.payload, state);
|
|
59
68
|
},
|
|
60
69
|
setPanes: (state, action: PayloadAction<PaneSpec[]>) => {
|
|
61
|
-
state.
|
|
70
|
+
state.panes = action.payload.map(pane => ({
|
|
71
|
+
name: pane.name,
|
|
72
|
+
hidden: !!pane.preHidden,
|
|
73
|
+
disabled: !!pane.preDisabled,
|
|
74
|
+
}));
|
|
75
|
+
|
|
76
|
+
if (
|
|
77
|
+
!state.currentPane ||
|
|
78
|
+
!getValidPanes(state.panes).find(
|
|
79
|
+
p => p.name === state.currentPane
|
|
80
|
+
)
|
|
81
|
+
) {
|
|
82
|
+
setCurrentPaneInState(
|
|
83
|
+
getValidPanes(state.panes)[0].name,
|
|
84
|
+
state
|
|
85
|
+
);
|
|
86
|
+
}
|
|
62
87
|
},
|
|
63
88
|
switchToNextPane: state => {
|
|
89
|
+
const validPanes = getValidPanes(state.panes);
|
|
90
|
+
const currentPaneIndex = state.panes.findIndex(
|
|
91
|
+
pane => pane.name === state.currentPane
|
|
92
|
+
);
|
|
64
93
|
setCurrentPaneInState(
|
|
65
|
-
(
|
|
94
|
+
validPanes[(currentPaneIndex + 1) % validPanes.length].name,
|
|
66
95
|
state
|
|
67
96
|
);
|
|
68
97
|
},
|
|
69
98
|
switchToPreviousPane: state => {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
99
|
+
const currentPaneIndex = state.panes.findIndex(
|
|
100
|
+
pane => pane.name === state.currentPane
|
|
101
|
+
);
|
|
102
|
+
setCurrentPaneInState(
|
|
103
|
+
getValidPanes(state.panes)[Math.max(0, currentPaneIndex - 1)]
|
|
104
|
+
.name,
|
|
105
|
+
state
|
|
106
|
+
);
|
|
107
|
+
},
|
|
108
|
+
setPaneHidden: (
|
|
109
|
+
state,
|
|
110
|
+
action: PayloadAction<{ name: string; hidden: boolean }>
|
|
111
|
+
) => {
|
|
112
|
+
state.panes = state.panes.map(pane =>
|
|
113
|
+
pane.name === action.payload.name
|
|
114
|
+
? { ...pane, hidden: action.payload.hidden }
|
|
115
|
+
: pane
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
if (
|
|
119
|
+
state.currentPane === action.payload.name &&
|
|
120
|
+
action.payload.hidden
|
|
121
|
+
) {
|
|
122
|
+
setCurrentPaneInState(
|
|
123
|
+
getValidPanes(state.panes)[0].name,
|
|
124
|
+
state
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
},
|
|
128
|
+
setPaneDisabled: (
|
|
129
|
+
state,
|
|
130
|
+
action: PayloadAction<{ name: string; disabled: boolean }>
|
|
131
|
+
) => {
|
|
132
|
+
state.panes = state.panes.map(pane =>
|
|
133
|
+
pane.name === action.payload.name
|
|
134
|
+
? { ...pane, disabled: action.payload.disabled }
|
|
135
|
+
: pane
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
if (
|
|
139
|
+
state.currentPane === action.payload.name &&
|
|
140
|
+
action.payload.disabled
|
|
141
|
+
) {
|
|
142
|
+
setCurrentPaneInState(
|
|
143
|
+
getValidPanes(state.panes)[0].name,
|
|
144
|
+
state
|
|
145
|
+
);
|
|
73
146
|
}
|
|
74
|
-
setCurrentPaneInState(nextPane, state);
|
|
75
147
|
},
|
|
76
148
|
},
|
|
77
149
|
});
|
|
@@ -85,15 +157,15 @@ export const {
|
|
|
85
157
|
toggleSidePanelVisible,
|
|
86
158
|
switchToNextPane,
|
|
87
159
|
switchToPreviousPane,
|
|
160
|
+
setPaneHidden,
|
|
161
|
+
setPaneDisabled,
|
|
88
162
|
},
|
|
89
163
|
} = slice;
|
|
90
164
|
|
|
91
165
|
export const isSidePanelVisible = (state: RootState) =>
|
|
92
166
|
state.appLayout.isSidePanelVisible;
|
|
93
167
|
export const isLogVisible = (state: RootState) => state.appLayout.isLogVisible;
|
|
94
|
-
export const
|
|
168
|
+
export const panes = (state: RootState) =>
|
|
169
|
+
state.appLayout.panes.filter(p => !p.hidden);
|
|
95
170
|
|
|
96
|
-
export const currentPane = ({ appLayout }: RootState) =>
|
|
97
|
-
appLayout.currentPane >= appLayout.paneNames.length
|
|
98
|
-
? 0
|
|
99
|
-
: appLayout.currentPane;
|
|
171
|
+
export const currentPane = ({ appLayout }: RootState) => appLayout.currentPane;
|
|
@@ -8,7 +8,12 @@ import React from 'react';
|
|
|
8
8
|
import { screen } from '@testing-library/react';
|
|
9
9
|
|
|
10
10
|
import render from '../../test/testrenderer';
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
setCurrentPane,
|
|
13
|
+
setPaneDisabled,
|
|
14
|
+
setPaneHidden,
|
|
15
|
+
setPanes,
|
|
16
|
+
} from '../App/appLayout';
|
|
12
17
|
import NavMenu from './NavMenu';
|
|
13
18
|
|
|
14
19
|
const aPane = {
|
|
@@ -38,4 +43,62 @@ describe('NavMenu', () => {
|
|
|
38
43
|
expect(screen.getByText('an menu item')).toBeInTheDocument();
|
|
39
44
|
expect(screen.getByText('another menu item')).toBeInTheDocument();
|
|
40
45
|
});
|
|
46
|
+
|
|
47
|
+
it('shows the selected item', () => {
|
|
48
|
+
render(<NavMenu />, [setPanes([aPane, anotherPane])]);
|
|
49
|
+
|
|
50
|
+
expect(screen.getByText('an menu item')).toBeHighlighted();
|
|
51
|
+
expect(screen.getByText('another menu item')).not.toBeHighlighted();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('reacts to changing the selected item', () => {
|
|
55
|
+
render(<NavMenu />, [
|
|
56
|
+
setPanes([aPane, anotherPane]),
|
|
57
|
+
setCurrentPane('another menu item'),
|
|
58
|
+
]);
|
|
59
|
+
|
|
60
|
+
expect(screen.getByText('an menu item')).not.toBeHighlighted();
|
|
61
|
+
expect(screen.getByText('another menu item')).toBeHighlighted();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('hides prehidden items', () => {
|
|
65
|
+
render(<NavMenu />, [
|
|
66
|
+
setPanes([{ ...aPane, preHidden: true }, anotherPane]),
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
expect(screen.queryByText('an menu item')).not.toBeInTheDocument();
|
|
70
|
+
expect(screen.getByText('another menu item')).toBeInTheDocument();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('reacts to hiding items', () => {
|
|
74
|
+
render(<NavMenu />, [
|
|
75
|
+
setPanes([aPane, anotherPane]),
|
|
76
|
+
setPaneHidden({ name: aPane.name, hidden: true }),
|
|
77
|
+
]);
|
|
78
|
+
|
|
79
|
+
expect(screen.queryByText('an menu item')).not.toBeInTheDocument();
|
|
80
|
+
expect(screen.getByText('another menu item')).toBeInTheDocument();
|
|
81
|
+
expect(screen.getByText('another menu item')).toBeHighlighted();
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('disables preDisabled items', () => {
|
|
85
|
+
render(<NavMenu />, [
|
|
86
|
+
setPanes([{ ...aPane, preDisabled: true }, anotherPane]),
|
|
87
|
+
]);
|
|
88
|
+
|
|
89
|
+
expect(screen.getByText('an menu item')).not.toBeEnabled();
|
|
90
|
+
expect(screen.getByText('another menu item')).toBeInTheDocument();
|
|
91
|
+
expect(screen.getByText('another menu item')).toBeHighlighted();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('reacts to disabling items', () => {
|
|
95
|
+
render(<NavMenu />, [
|
|
96
|
+
setPanes([aPane, anotherPane]),
|
|
97
|
+
setPaneDisabled({ name: aPane.name, disabled: true }),
|
|
98
|
+
]);
|
|
99
|
+
|
|
100
|
+
expect(screen.getByText('an menu item')).not.toBeEnabled();
|
|
101
|
+
expect(screen.getByText('another menu item')).toBeInTheDocument();
|
|
102
|
+
expect(screen.getByText('another menu item')).toBeHighlighted();
|
|
103
|
+
});
|
|
41
104
|
});
|
package/src/NavBar/NavMenu.tsx
CHANGED
|
@@ -9,7 +9,7 @@ import { useDispatch, useSelector } from 'react-redux';
|
|
|
9
9
|
|
|
10
10
|
import {
|
|
11
11
|
currentPane as currentPaneSelector,
|
|
12
|
-
|
|
12
|
+
panes as panesSelector,
|
|
13
13
|
switchToNextPane,
|
|
14
14
|
switchToPreviousPane,
|
|
15
15
|
} from '../App/appLayout';
|
|
@@ -18,7 +18,7 @@ import NavMenuItem from './NavMenuItem';
|
|
|
18
18
|
|
|
19
19
|
const NavMenu = () => {
|
|
20
20
|
const currentPane = useSelector(currentPaneSelector);
|
|
21
|
-
const
|
|
21
|
+
const panes = useSelector(panesSelector);
|
|
22
22
|
const dispatch = useDispatch();
|
|
23
23
|
|
|
24
24
|
useHotKey({
|
|
@@ -37,12 +37,12 @@ const NavMenu = () => {
|
|
|
37
37
|
|
|
38
38
|
return (
|
|
39
39
|
<div data-testid="nav-menu" className="d-flex ml-3 flex-wrap">
|
|
40
|
-
{
|
|
40
|
+
{panes.map(pane => (
|
|
41
41
|
<NavMenuItem
|
|
42
|
-
key={name}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
42
|
+
key={pane.name}
|
|
43
|
+
isSelected={currentPane === pane.name}
|
|
44
|
+
label={pane.name}
|
|
45
|
+
disabled={pane.disabled}
|
|
46
46
|
/>
|
|
47
47
|
))}
|
|
48
48
|
</div>
|
|
@@ -13,12 +13,12 @@ import classNames from '../utils/classNames';
|
|
|
13
13
|
import './nav-menu-item.scss';
|
|
14
14
|
|
|
15
15
|
interface Props {
|
|
16
|
-
index: number;
|
|
17
16
|
isSelected: boolean;
|
|
18
17
|
label: string;
|
|
18
|
+
disabled: boolean;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
const NavMenuItem: FC<Props> = ({
|
|
21
|
+
const NavMenuItem: FC<Props> = ({ isSelected, label, disabled }) => {
|
|
22
22
|
const dispatch = useDispatch();
|
|
23
23
|
|
|
24
24
|
return (
|
|
@@ -29,7 +29,8 @@ const NavMenuItem: FC<Props> = ({ index, isSelected, label }) => {
|
|
|
29
29
|
isSelected && 'selected',
|
|
30
30
|
'mr-4'
|
|
31
31
|
)}
|
|
32
|
-
onClick={() => dispatch(setCurrentPane(
|
|
32
|
+
onClick={() => dispatch(setCurrentPane(label))}
|
|
33
|
+
disabled={disabled}
|
|
33
34
|
>
|
|
34
35
|
{label}
|
|
35
36
|
</button>
|
package/src/index.ts
CHANGED
|
@@ -85,7 +85,12 @@ export { truncateMiddle } from './utils/truncateMiddle';
|
|
|
85
85
|
export { default as useHotKey } from './utils/useHotKey';
|
|
86
86
|
export { isDevelopment } from './utils/environment';
|
|
87
87
|
|
|
88
|
-
export {
|
|
88
|
+
export {
|
|
89
|
+
currentPane,
|
|
90
|
+
setCurrentPane,
|
|
91
|
+
setPaneHidden,
|
|
92
|
+
setPaneDisabled,
|
|
93
|
+
} from './App/appLayout';
|
|
89
94
|
|
|
90
95
|
export { isLoggingVerbose } from './Log/logSlice';
|
|
91
96
|
|
|
@@ -137,9 +137,10 @@ export const getTelemetryClientId = () =>
|
|
|
137
137
|
let appSpecificStore: Store | undefined;
|
|
138
138
|
|
|
139
139
|
interface SharedAppSpecificStoreSchema {
|
|
140
|
-
currentPane?:
|
|
140
|
+
currentPane?: string;
|
|
141
141
|
isLogVisible?: boolean;
|
|
142
142
|
isLoggingVerbose?: boolean;
|
|
143
|
+
currentPaneName?: string;
|
|
143
144
|
}
|
|
144
145
|
|
|
145
146
|
export const getAppSpecificStore = <
|
|
@@ -164,13 +165,14 @@ export const getAppSpecificStore = <
|
|
|
164
165
|
>;
|
|
165
166
|
};
|
|
166
167
|
|
|
167
|
-
export const persistCurrentPane = (currentPane:
|
|
168
|
+
export const persistCurrentPane = (currentPane: string) =>
|
|
168
169
|
getAppSpecificStore<SharedAppSpecificStoreSchema>().set(
|
|
169
|
-
`
|
|
170
|
+
`currentPaneName`,
|
|
170
171
|
currentPane
|
|
171
172
|
);
|
|
172
173
|
export const getPersistedCurrentPane = () =>
|
|
173
|
-
getAppSpecificStore<SharedAppSpecificStoreSchema>().get(`
|
|
174
|
+
getAppSpecificStore<SharedAppSpecificStoreSchema>().get(`currentPaneName`);
|
|
175
|
+
|
|
174
176
|
export const persistLogVisible = (visible: boolean) =>
|
|
175
177
|
getAppSpecificStore<SharedAppSpecificStoreSchema>().set(
|
|
176
178
|
`isLogVisible`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MetaFiles.d.ts","sourceRoot":"","sources":["../../../ipc/MetaFiles.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC;AAE/B,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,MAAM,MAAM,aAAa,GAAG,SAAS,EAAE,CAAC;AAExC,MAAM,MAAM,WAAW,GAAG;IACtB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,SAAS,CAAC;IACtB,cAAc,CAAC,EAAE,cAAc,CAAC;CACnC,CAAC;AAEF,MAAM,WAAW,OAAO;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,SAAS,CAAC;IACnB,eAAe,EAAE,SAAS,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,WAAW,CAAC;IACtB,SAAS,CAAC,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACL;AAED,eAAO,MAAM,MAAM,aAIlB,CAAC;AAEF,QAAA,MAAM,iBAAiB,aAAa,CAAC;AACrC,QAAA,MAAM,oBAAoB,aAAS,CAAC;AAEpC,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAClE,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE,eAAO,MAAM,UAAU,iEAGtB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"MetaFiles.d.ts","sourceRoot":"","sources":["../../../ipc/MetaFiles.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,MAAM,SAAS,GAAG,MAAM,CAAC;AAE/B,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,SAAS,EAAE,CAAC;CACrB;AAED,MAAM,MAAM,aAAa,GAAG,SAAS,EAAE,CAAC;AAExC,MAAM,MAAM,WAAW,GAAG;IACtB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAAC;CACjC,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,SAAS,CAAC;IACtB,cAAc,CAAC,EAAE,cAAc,CAAC;CACnC,CAAC;AAEF,MAAM,WAAW,OAAO;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,OAAO,EAAE,SAAS,CAAC;IACnB,eAAe,EAAE,SAAS,CAAC;IAC3B,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,WAAW,CAAC;IACtB,SAAS,CAAC,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACL;AAED,eAAO,MAAM,MAAM,aAIlB,CAAC;AAEF,QAAA,MAAM,iBAAiB,aAAa,CAAC;AACrC,QAAA,MAAM,oBAAoB,aAAS,CAAC;AAEpC,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAClE,MAAM,MAAM,oBAAoB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,oBAAoB,CAAC,CAAC;AAExE,eAAO,MAAM,UAAU,iEAGtB,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../../ipc/apps.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEtD,MAAM,WAAW,OAAO;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;CACtB;AAED,UAAU,OAAO;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,YAAY;IAClB,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,SAAS;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE;QACP,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACL;AAED,MAAM,WAAW,QAAS,SAAQ,SAAS,EAAE,OAAO;IAChD,MAAM,EAAE,OAAO,KAAK,CAAC;CACxB;AAED,MAAM,WAAW,wBACb,SAAQ,OAAO,EACX,SAAS,EACT,YAAY;IAChB,WAAW,EAAE,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,0BAA2B,SAAQ,OAAO,EAAE,YAAY;IACrE,WAAW,EAAE,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,YAAa,SAAQ,OAAO,EAAE,SAAS,EAAE,YAAY;IAClE,WAAW,EAAE,IAAI,CAAC;CACrB;AAED,MAAM,MAAM,eAAe,GACrB,wBAAwB,GACxB,0BAA0B,GAC1B,YAAY,CAAC;AAEnB,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,wBAAwB,GAAG,YAAY,CAAC;AAE/E,MAAM,MAAM,GAAG,GAAG,QAAQ,GAAG,eAAe,CAAC;AAE7C,MAAM,WAAW,YAAa,SAAQ,OAAO;IACzC,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CAChB;AAOD,MAAM,MAAM,eAAe,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAElE,eAAO,MAAM,cAAc,SAAU,GAAG,2BACA,CAAC;AAEzC,eAAO,MAAM,WAAW,SAAU,GAAG,yBACA,CAAC;AAEtC,eAAO,MAAM,WAAW,SAAU,GAAG,wBACK,CAAC;AAa3C,eAAO,MAAM,WAAW,SAAU,GAAG,oCAKU,CAAC;AAGhD,KAAK,yBAAyB,GAAG;IAC7B,IAAI,EAAE,eAAe,EAAE,CAAC;IACxB,cAAc,EAAE,YAAY,EAAE,CAAC;IAC/B,iBAAiB,EAAE,eAAe,EAAE,CAAC;CACxC,CAAC;AAwBF,eAAO,MAAM,WAAW;;;CAGvB,CAAC;AAEF,eAAO,MAAM,MAAM;;;2BA7DkB,GAAG;wBAGN,GAAG;wBAGH,GAAG;wBAcH,GAAG;CAiDpC,CAAC"}
|
|
1
|
+
{"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../../ipc/apps.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEtD,MAAM,WAAW,OAAO;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,UAAU,CAAC;CACtB;AAED,UAAU,OAAO;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,UAAU,YAAY;IAClB,MAAM,EAAE,UAAU,CAAC;IACnB,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,QAAQ,CAAC,EAAE,WAAW,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,SAAS;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE;QACP,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC;CACL;AAED,MAAM,WAAW,QAAS,SAAQ,SAAS,EAAE,OAAO;IAChD,MAAM,EAAE,OAAO,KAAK,CAAC;CACxB;AAED,MAAM,WAAW,wBACb,SAAQ,OAAO,EACX,SAAS,EACT,YAAY;IAChB,WAAW,EAAE,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,0BAA2B,SAAQ,OAAO,EAAE,YAAY;IACrE,WAAW,EAAE,KAAK,CAAC;CACtB;AAED,MAAM,WAAW,YAAa,SAAQ,OAAO,EAAE,SAAS,EAAE,YAAY;IAClE,WAAW,EAAE,IAAI,CAAC;CACrB;AAED,MAAM,MAAM,eAAe,GACrB,wBAAwB,GACxB,0BAA0B,GAC1B,YAAY,CAAC;AAEnB,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,wBAAwB,GAAG,YAAY,CAAC;AAE/E,MAAM,MAAM,GAAG,GAAG,QAAQ,GAAG,eAAe,CAAC;AAE7C,MAAM,WAAW,YAAa,SAAQ,OAAO;IACzC,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CAChB;AAOD,MAAM,MAAM,eAAe,GAAG;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAElE,eAAO,MAAM,cAAc,SAAU,GAAG,2BACA,CAAC;AAEzC,eAAO,MAAM,WAAW,SAAU,GAAG,yBACA,CAAC;AAEtC,eAAO,MAAM,WAAW,SAAU,GAAG,wBACK,CAAC;AAa3C,eAAO,MAAM,WAAW,SAAU,GAAG,oCAKU,CAAC;AAGhD,KAAK,yBAAyB,GAAG;IAC7B,IAAI,EAAE,eAAe,EAAE,CAAC;IACxB,cAAc,EAAE,YAAY,EAAE,CAAC;IAC/B,iBAAiB,EAAE,eAAe,EAAE,CAAC;CACxC,CAAC;AAwBF,eAAO,MAAM,WAAW;;;CAGvB,CAAC;AAEF,eAAO,MAAM,MAAM;;;2BA7DkB,GAAG;wBAGN,GAAG;wBAGH,GAAG;wBAcH,GAAG;CAiDpC,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../../src/App/App.tsx"],"names":[],"mappings":"AAMA,OAAO,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,EAA8B,MAAM,OAAO,CAAC;AAIzE,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"App.d.ts","sourceRoot":"","sources":["../../../../src/App/App.tsx"],"names":[],"mappings":"AAMA,OAAO,eAAe,CAAC;AAEvB,OAAO,KAAK,EAAE,EAAE,EAAE,EAAE,SAAS,EAA8B,MAAM,OAAO,CAAC;AAIzE,OAAO,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAsChC,OAAO,YAAY,CAAC;AACpB,OAAO,eAAe,CAAC;AACvB,OAAO,gBAAgB,CAAC;AAExB,MAAM,WAAW,SAAS;IACtB,MAAM,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,IAAI;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,CAAC;IACpB,SAAS,CAAC,EAAE,EAAE,CAAC;CAClB;AAED,UAAU,iBAAiB;IACvB,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,SAAS,EAAE,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC9B,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACnC;;;;AAoID,wBASE;AA2CF,eAAO,MAAM,MAAM,QAAS,MAAM,YAAY,SAM7C,CAAC"}
|