@nordicsemiconductor/pc-nrfconnect-shared 220.0.0 → 223.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 +27 -0
- package/README.md +30 -21
- package/config/tailwind.config.js +5 -1
- package/ipc/apps.ts +3 -12
- package/ipc/sources.ts +0 -5
- package/package.json +1 -1
- package/release_notes.md +3 -6
- package/scripts/check-app-properties.ts +1 -1
- package/scripts/check-for-typescript.ts +1 -1
- package/scripts/create-source.ts +1 -1
- package/scripts/esbuild.ts +1 -1
- package/scripts/installHusky.ts +1 -1
- package/scripts/is-releasable.ts +2 -2
- package/scripts/latest-changelog-entry.test.ts +4 -4
- package/scripts/latest-changelog-entry.ts +1 -1
- package/scripts/nordic-publish.js +1 -1
- package/scripts/nordic-publish.ts +1 -1
- package/scripts/nrfconnect-license.ts +1 -1
- package/scripts/postinstall.ts +1 -1
- package/scripts/prepare-shared-release.ts +1 -1
- package/src/Device/DeviceSelector/DeviceSelector.test.tsx +11 -11
- package/src/Dialog/Dialog.test.tsx +9 -10
- package/src/Dropdown/Dropdown.test.tsx +3 -3
- package/src/Dropdown/Dropdown.tsx +15 -4
- package/src/Dropdown/DropdownHelpers.test.ts +20 -21
- package/src/ErrorBoundary/ErrorBoundary.test.tsx +4 -4
- package/src/ErrorDialog/ErrorDialog.test.tsx +3 -3
- package/src/ErrorDialog/errorDialogSlice.test.ts +5 -5
- package/src/FactoryReset/FactoryResetButton.test.tsx +23 -17
- package/src/Group/Group.tsx +1 -1
- package/src/InlineInput/InlineInput.tsx +3 -0
- package/src/InlineInput/NumberInlineInput.tsx +23 -0
- package/src/Slider/Factor.test.ts +4 -4
- package/src/index.ts +0 -2
- package/src/logging/appTransport.test.ts +6 -6
- package/src/logging/logBuffer.test.ts +4 -4
- package/typings/generated/ipc/apps.d.ts +5 -11
- package/typings/generated/ipc/apps.d.ts.map +1 -1
- package/typings/generated/ipc/sources.d.ts +0 -7
- package/typings/generated/ipc/sources.d.ts.map +1 -1
- package/typings/generated/main/index.d.ts +1 -9
- package/typings/generated/main/index.d.ts.map +1 -1
- package/typings/generated/scripts/check-app-properties.d.ts +1 -1
- package/typings/generated/scripts/check-for-typescript.d.ts +1 -1
- package/typings/generated/scripts/create-source.d.ts +1 -1
- package/typings/generated/scripts/esbuild.d.ts +1 -1
- package/typings/generated/scripts/installHusky.d.ts +1 -1
- package/typings/generated/scripts/is-releasable.d.ts +1 -1
- package/typings/generated/scripts/latest-changelog-entry.d.ts +1 -1
- package/typings/generated/scripts/nordic-publish.d.ts +1 -1
- package/typings/generated/scripts/nrfconnect-license.d.ts +1 -1
- package/typings/generated/scripts/postinstall.d.ts +1 -1
- package/typings/generated/scripts/prepare-shared-release.d.ts +1 -1
- package/typings/generated/src/Dropdown/Dropdown.d.ts +2 -1
- package/typings/generated/src/Dropdown/Dropdown.d.ts.map +1 -1
- package/typings/generated/src/InlineInput/InlineInput.d.ts +1 -0
- package/typings/generated/src/InlineInput/InlineInput.d.ts.map +1 -1
- package/typings/generated/src/InlineInput/NumberInlineInput.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/Changelog.md
CHANGED
|
@@ -7,6 +7,33 @@ 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
|
+
## 223.0.0 - 2025-07-28
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Return value of `getDownloadableApps` has less fields now and some more
|
|
15
|
+
exports were removed, because they were only needed in the launcher and
|
|
16
|
+
having them in shared made changes harder in the launcher.
|
|
17
|
+
|
|
18
|
+
## 222.0.0 - 2025-07-23
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- Automatic publishing of shared.
|
|
23
|
+
|
|
24
|
+
## 221.0.0 - 2025-07-21
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- Custom tailwind font-size `text-2xs` (0.625rem/10px).
|
|
29
|
+
- Narrower Dropdown variant.
|
|
30
|
+
- Automatic character limit derivation for number input components based on
|
|
31
|
+
their range constraints.
|
|
32
|
+
|
|
33
|
+
### Fixed
|
|
34
|
+
|
|
35
|
+
- Running build scripts failed on Windows.
|
|
36
|
+
|
|
10
37
|
## 220.0.0 - 2025-07-16
|
|
11
38
|
|
|
12
39
|
### Added
|
package/README.md
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
# Shared commodities for developing nRF Connect for Desktop
|
|
2
2
|
|
|
3
|
-
[](https://dev.azure.com/NordicSemiconductor/Wayland/_build/latest?definitionId=31&branchName=master)
|
|
4
|
-
|
|
5
3
|
This project provides shared commodities for developing nRF Connect for Desktop
|
|
6
4
|
apps and their launcher:
|
|
7
5
|
|
|
@@ -10,30 +8,41 @@ apps and their launcher:
|
|
|
10
8
|
- Configurations
|
|
11
9
|
- Test facilities
|
|
12
10
|
|
|
11
|
+
## Developing a new feature or fixing an error
|
|
12
|
+
|
|
13
|
+
Whenever something is changed in pc-nrfconnect-shared, an entry should be added
|
|
14
|
+
to `Changelog.md`.
|
|
15
|
+
|
|
16
|
+
If there is no latest entry there yet, and you do not intend to release the
|
|
17
|
+
change as a new version right ahead, add a new section with the heading
|
|
18
|
+
`## Unreleased` at the top.
|
|
19
|
+
|
|
13
20
|
## Releasing
|
|
14
21
|
|
|
15
|
-
|
|
16
|
-
|
|
22
|
+
To release, two files must be up-to-date:
|
|
23
|
+
|
|
24
|
+
- `package.json` contain the correct version number (one more than the last
|
|
25
|
+
release).
|
|
26
|
+
- `Changelog.md` must contain an entry, with that version number and today's
|
|
27
|
+
date.
|
|
17
28
|
|
|
18
|
-
|
|
29
|
+
By running `npm run prepare-shared-release` you update the version in
|
|
30
|
+
`package.json` and in `Changelog.md` a potential `## Unreleased` heading is
|
|
31
|
+
updated to the right version and today‘s date.
|
|
19
32
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
`## X.0.0 - YYYY-MM-DD`.
|
|
23
|
-
- Commit and push your changes
|
|
33
|
+
When those conditions are met, a new release of shared will automatically be
|
|
34
|
+
created when the according PR is merged into main.
|
|
24
35
|
|
|
25
|
-
|
|
36
|
+
## Unpublishing a version
|
|
26
37
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
action.
|
|
30
|
-
- Click "Run workflow".
|
|
31
|
-
- Optionally select a ref to release, but usually this should be `main` and
|
|
32
|
-
can be left empty.
|
|
38
|
+
If you need to unpublish a specific version from npm (e.g., due to a critical
|
|
39
|
+
bug), you can use the "Unpublish npm version" GitHub Action:
|
|
33
40
|
|
|
34
|
-
|
|
41
|
+
1. Go to the
|
|
42
|
+
[Unpublish npm version GitHub Action](https://github.com/NordicSemiconductor/pc-nrfconnect-shared/actions/workflows/unpublish-npm-version.yml)
|
|
43
|
+
and run the workflow.
|
|
44
|
+
1. Enter the version to unpublish (e.g., `221.0.0`)
|
|
35
45
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
- Publish to npm.
|
|
46
|
+
**Warning:** Unpublishing a version from npm is irreversible and should only be
|
|
47
|
+
done in exceptional circumstances (e.g., security vulnerabilities, critical
|
|
48
|
+
bugs).
|
package/ipc/apps.ts
CHANGED
|
@@ -11,7 +11,7 @@ import type {
|
|
|
11
11
|
NrfutilModuleVersion,
|
|
12
12
|
UrlString,
|
|
13
13
|
} from './MetaFiles';
|
|
14
|
-
import { LOCAL,
|
|
14
|
+
import { LOCAL, SourceName } from './sources';
|
|
15
15
|
|
|
16
16
|
export interface AppSpec {
|
|
17
17
|
name: string;
|
|
@@ -75,18 +75,11 @@ export type LaunchableApp = LocalApp | InstalledDownloadableApp | WithdrawnApp;
|
|
|
75
75
|
|
|
76
76
|
export type App = LocalApp | DownloadableApp;
|
|
77
77
|
|
|
78
|
-
export
|
|
79
|
-
reason: unknown;
|
|
80
|
-
path: string;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const channel = {
|
|
78
|
+
export const channel = {
|
|
84
79
|
getDownloadableApps: 'apps:get-downloadable-apps',
|
|
85
80
|
installDownloadableApp: 'apps:install-downloadable-app',
|
|
86
81
|
};
|
|
87
82
|
|
|
88
|
-
export type SourceWithError = { source: Source; reason?: string };
|
|
89
|
-
|
|
90
83
|
export const isDownloadable = (app?: App): app is DownloadableApp =>
|
|
91
84
|
app != null && app?.source !== LOCAL;
|
|
92
85
|
|
|
@@ -115,10 +108,8 @@ export const isUpdatable = (app?: App): app is InstalledDownloadableApp =>
|
|
|
115
108
|
latestVersionHasDifferentChecksum(app));
|
|
116
109
|
|
|
117
110
|
// getDownloadableApps
|
|
118
|
-
type GetDownloadableAppsResult = {
|
|
111
|
+
export type GetDownloadableAppsResult = {
|
|
119
112
|
apps: DownloadableApp[];
|
|
120
|
-
appsWithErrors: AppWithError[];
|
|
121
|
-
sourcesWithErrors: SourceWithError[];
|
|
122
113
|
};
|
|
123
114
|
|
|
124
115
|
type GetDownloadableApps = () => GetDownloadableAppsResult;
|
package/ipc/sources.ts
CHANGED
|
@@ -4,16 +4,11 @@
|
|
|
4
4
|
* SPDX-License-Identifier: LicenseRef-Nordic-4-Clause
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import { UrlString } from './MetaFiles';
|
|
8
|
-
|
|
9
7
|
enum StandardSourceNames {
|
|
10
8
|
OFFICIAL = 'official',
|
|
11
9
|
LOCAL = 'local',
|
|
12
10
|
}
|
|
13
11
|
|
|
14
12
|
export const { LOCAL, OFFICIAL } = StandardSourceNames;
|
|
15
|
-
export const allStandardSourceNames: SourceName[] = [OFFICIAL, LOCAL];
|
|
16
13
|
|
|
17
14
|
export type SourceName = string;
|
|
18
|
-
export type SourceUrl = UrlString;
|
|
19
|
-
export type Source = { name: SourceName; url: SourceUrl };
|
package/package.json
CHANGED
package/release_notes.md
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
### Added
|
|
2
|
-
|
|
3
|
-
- Option to persist the Group collapse state.
|
|
4
|
-
|
|
5
1
|
### Changed
|
|
6
2
|
|
|
7
|
-
-
|
|
8
|
-
|
|
3
|
+
- Return value of `getDownloadableApps` has less fields now and some more
|
|
4
|
+
exports were removed, because they were only needed in the launcher and
|
|
5
|
+
having them in shared made changes harder in the launcher.
|
package/scripts/create-source.ts
CHANGED
package/scripts/esbuild.ts
CHANGED
package/scripts/installHusky.ts
CHANGED
package/scripts/is-releasable.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
2
|
|
|
3
3
|
/*
|
|
4
4
|
* Copyright (c) 2025 Nordic Semiconductor ASA
|
|
@@ -18,7 +18,7 @@ import getReleaseNumbers from './get-release-numbers';
|
|
|
18
18
|
import { getLatestEntry } from './latest-changelog-entry';
|
|
19
19
|
|
|
20
20
|
const fail = (message: string) => {
|
|
21
|
-
console.log(
|
|
21
|
+
console.log(message);
|
|
22
22
|
process.exit(1);
|
|
23
23
|
};
|
|
24
24
|
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { getLatestEntry } from './latest-changelog-entry';
|
|
8
8
|
|
|
9
9
|
describe('getLatestEntry', () => {
|
|
10
|
-
it('
|
|
10
|
+
it('extracts the latest changelog entry', () => {
|
|
11
11
|
const changelog = `# Changelog
|
|
12
12
|
|
|
13
13
|
All notable changes to this project will be documented in this file.
|
|
@@ -29,7 +29,7 @@ All notable changes to this project will be documented in this file.
|
|
|
29
29
|
expect(result.content).toBe('### Changed\n\n- Something');
|
|
30
30
|
});
|
|
31
31
|
|
|
32
|
-
it('
|
|
32
|
+
it('handles changelog with only one entry', () => {
|
|
33
33
|
const changelog = `# Changelog
|
|
34
34
|
|
|
35
35
|
All notable changes to this project will be documented in this file.
|
|
@@ -46,7 +46,7 @@ All notable changes to this project will be documented in this file.
|
|
|
46
46
|
expect(result.content).toBe('### Added\n\n- Something else');
|
|
47
47
|
});
|
|
48
48
|
|
|
49
|
-
it('
|
|
49
|
+
it('handles changelog with empty content', () => {
|
|
50
50
|
const changelog = `# Changelog
|
|
51
51
|
|
|
52
52
|
All notable changes to this project will be documented in this file.
|
|
@@ -65,7 +65,7 @@ All notable changes to this project will be documented in this file.
|
|
|
65
65
|
expect(result.content).toBe('');
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
-
it('
|
|
68
|
+
it('handles changelog with nothing before the first entry', () => {
|
|
69
69
|
const changelog = `## 33.0.0 - 2022-02-01
|
|
70
70
|
|
|
71
71
|
### Added
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env
|
|
1
|
+
#!/usr/bin/env tsx
|
|
2
2
|
"use strict";var Cd=Object.create;var Us=Object.defineProperty;var gd=Object.getOwnPropertyDescriptor;var Dd=Object.getOwnPropertyNames;var _d=Object.getPrototypeOf,Bd=Object.prototype.hasOwnProperty;var A=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var yd=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Dd(e))!Bd.call(t,i)&&i!==r&&Us(t,i,{get:()=>e[i],enumerable:!(n=gd(e,i))||n.enumerable});return t};var Dt=(t,e,r)=>(r=t!=null?Cd(_d(t)):{},yd(e||!t||!t.__esModule?Us(r,"default",{value:t,enumerable:!0}):r,t));var jr=A(pi=>{var Cn=class extends Error{constructor(e,r,n){super(n),Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name,this.code=r,this.exitCode=e,this.nestedError=void 0}},hi=class extends Cn{constructor(e){super(1,"commander.invalidArgument",e),Error.captureStackTrace(this,this.constructor),this.name=this.constructor.name}};pi.CommanderError=Cn;pi.InvalidArgumentError=hi});var gn=A(Fi=>{var{InvalidArgumentError:vd}=jr(),Ai=class{constructor(e,r){switch(this.description=r||"",this.variadic=!1,this.parseArg=void 0,this.defaultValue=void 0,this.defaultValueDescription=void 0,this.argChoices=void 0,e[0]){case"<":this.required=!0,this._name=e.slice(1,-1);break;case"[":this.required=!1,this._name=e.slice(1,-1);break;default:this.required=!0,this._name=e;break}this._name.length>3&&this._name.slice(-3)==="..."&&(this.variadic=!0,this._name=this._name.slice(0,-3))}name(){return this._name}_concatValue(e,r){return r===this.defaultValue||!Array.isArray(r)?[e]:r.concat(e)}default(e,r){return this.defaultValue=e,this.defaultValueDescription=r,this}argParser(e){return this.parseArg=e,this}choices(e){return this.argChoices=e.slice(),this.parseArg=(r,n)=>{if(!this.argChoices.includes(r))throw new vd(`Allowed choices are ${this.argChoices.join(", ")}.`);return this.variadic?this._concatValue(r,n):r},this}argRequired(){return this.required=!0,this}argOptional(){return this.required=!1,this}};function bd(t){let e=t.name()+(t.variadic===!0?"...":"");return t.required?"<"+e+">":"["+e+"]"}Fi.Argument=Ai;Fi.humanReadableArgName=bd});var mi=A(Hs=>{var{humanReadableArgName:xd}=gn(),Ei=class{constructor(){this.helpWidth=void 0,this.sortSubcommands=!1,this.sortOptions=!1,this.showGlobalOptions=!1}visibleCommands(e){let r=e.commands.filter(n=>!n._hidden);if(e._hasImplicitHelpCommand()){let[,n,i]=e._helpCommandnameAndArgs.match(/([^ ]+) *(.*)/),s=e.createCommand(n).helpOption(!1);s.description(e._helpCommandDescription),i&&s.arguments(i),r.push(s)}return this.sortSubcommands&&r.sort((n,i)=>n.name().localeCompare(i.name())),r}compareOptions(e,r){let n=i=>i.short?i.short.replace(/^-/,""):i.long.replace(/^--/,"");return n(e).localeCompare(n(r))}visibleOptions(e){let r=e.options.filter(s=>!s.hidden),n=e._hasHelpOption&&e._helpShortFlag&&!e._findOption(e._helpShortFlag),i=e._hasHelpOption&&!e._findOption(e._helpLongFlag);if(n||i){let s;n?i?s=e.createOption(e._helpFlags,e._helpDescription):s=e.createOption(e._helpShortFlag,e._helpDescription):s=e.createOption(e._helpLongFlag,e._helpDescription),r.push(s)}return this.sortOptions&&r.sort(this.compareOptions),r}visibleGlobalOptions(e){if(!this.showGlobalOptions)return[];let r=[];for(let n=e.parent;n;n=n.parent){let i=n.options.filter(s=>!s.hidden);r.push(...i)}return this.sortOptions&&r.sort(this.compareOptions),r}visibleArguments(e){return e._argsDescription&&e._args.forEach(r=>{r.description=r.description||e._argsDescription[r.name()]||""}),e._args.find(r=>r.description)?e._args:[]}subcommandTerm(e){let r=e._args.map(n=>xd(n)).join(" ");return e._name+(e._aliases[0]?"|"+e._aliases[0]:"")+(e.options.length?" [options]":"")+(r?" "+r:"")}optionTerm(e){return e.flags}argumentTerm(e){return e.name()}longestSubcommandTermLength(e,r){return r.visibleCommands(e).reduce((n,i)=>Math.max(n,r.subcommandTerm(i).length),0)}longestOptionTermLength(e,r){return r.visibleOptions(e).reduce((n,i)=>Math.max(n,r.optionTerm(i).length),0)}longestGlobalOptionTermLength(e,r){return r.visibleGlobalOptions(e).reduce((n,i)=>Math.max(n,r.optionTerm(i).length),0)}longestArgumentTermLength(e,r){return r.visibleArguments(e).reduce((n,i)=>Math.max(n,r.argumentTerm(i).length),0)}commandUsage(e){let r=e._name;e._aliases[0]&&(r=r+"|"+e._aliases[0]);let n="";for(let i=e.parent;i;i=i.parent)n=i.name()+" "+n;return n+r+" "+e.usage()}commandDescription(e){return e.description()}subcommandDescription(e){return e.summary()||e.description()}optionDescription(e){let r=[];return e.argChoices&&r.push(`choices: ${e.argChoices.map(n=>JSON.stringify(n)).join(", ")}`),e.defaultValue!==void 0&&(e.required||e.optional||e.isBoolean()&&typeof e.defaultValue=="boolean")&&r.push(`default: ${e.defaultValueDescription||JSON.stringify(e.defaultValue)}`),e.presetArg!==void 0&&e.optional&&r.push(`preset: ${JSON.stringify(e.presetArg)}`),e.envVar!==void 0&&r.push(`env: ${e.envVar}`),r.length>0?`${e.description} (${r.join(", ")})`:e.description}argumentDescription(e){let r=[];if(e.argChoices&&r.push(`choices: ${e.argChoices.map(n=>JSON.stringify(n)).join(", ")}`),e.defaultValue!==void 0&&r.push(`default: ${e.defaultValueDescription||JSON.stringify(e.defaultValue)}`),r.length>0){let n=`(${r.join(", ")})`;return e.description?`${e.description} ${n}`:n}return e.description}formatHelp(e,r){let n=r.padWidth(e,r),i=r.helpWidth||80,s=2,a=2;function o(x,C){if(C){let T=`${x.padEnd(n+a)}${C}`;return r.wrap(T,i-s,n+a)}return x}function u(x){return x.join(`
|
|
3
3
|
`).replace(/^/gm," ".repeat(s))}let c=[`Usage: ${r.commandUsage(e)}`,""],l=r.commandDescription(e);l.length>0&&(c=c.concat([r.wrap(l,i,0),""]));let f=r.visibleArguments(e).map(x=>o(r.argumentTerm(x),r.argumentDescription(x)));f.length>0&&(c=c.concat(["Arguments:",u(f),""]));let m=r.visibleOptions(e).map(x=>o(r.optionTerm(x),r.optionDescription(x)));if(m.length>0&&(c=c.concat(["Options:",u(m),""])),this.showGlobalOptions){let x=r.visibleGlobalOptions(e).map(C=>o(r.optionTerm(C),r.optionDescription(C)));x.length>0&&(c=c.concat(["Global Options:",u(x),""]))}let F=r.visibleCommands(e).map(x=>o(r.subcommandTerm(x),r.subcommandDescription(x)));return F.length>0&&(c=c.concat(["Commands:",u(F),""])),c.join(`
|
|
4
4
|
`)}padWidth(e,r){return Math.max(r.longestOptionTermLength(e,r),r.longestGlobalOptionTermLength(e,r),r.longestSubcommandTermLength(e,r),r.longestArgumentTermLength(e,r))}wrap(e,r,n,i=40){let s=" \\f\\t\\v\xA0\u1680\u2000-\u200A\u202F\u205F\u3000\uFEFF",a=new RegExp(`[\\n][${s}]+`);if(e.match(a))return e;let o=r-n;if(o<i)return e;let u=e.slice(0,n),c=e.slice(n).replace(`\r
|
package/scripts/postinstall.ts
CHANGED
|
@@ -105,7 +105,7 @@ const validFirmware = {
|
|
|
105
105
|
};
|
|
106
106
|
|
|
107
107
|
describe('DeviceSelector', () => {
|
|
108
|
-
it('
|
|
108
|
+
it('has no device selected by default', () => {
|
|
109
109
|
render(
|
|
110
110
|
<DeviceSelector
|
|
111
111
|
deviceListing={{
|
|
@@ -119,7 +119,7 @@ describe('DeviceSelector', () => {
|
|
|
119
119
|
expect(screen.getByText('Select device')).toBeInTheDocument();
|
|
120
120
|
});
|
|
121
121
|
|
|
122
|
-
it('
|
|
122
|
+
it('shows an information when no devices are connected', () => {
|
|
123
123
|
render(
|
|
124
124
|
<DeviceSelector
|
|
125
125
|
deviceListing={{
|
|
@@ -134,7 +134,7 @@ describe('DeviceSelector', () => {
|
|
|
134
134
|
expect(screen.getByText('Nordic development kit')).toBeInTheDocument();
|
|
135
135
|
});
|
|
136
136
|
|
|
137
|
-
it('
|
|
137
|
+
it('shows a list of connected devices', () => {
|
|
138
138
|
render(
|
|
139
139
|
<DeviceSelector
|
|
140
140
|
deviceListing={{
|
|
@@ -149,7 +149,7 @@ describe('DeviceSelector', () => {
|
|
|
149
149
|
expect(screen.getByText(DEVICE_SERIAL_NUMBER)).toBeInTheDocument();
|
|
150
150
|
});
|
|
151
151
|
|
|
152
|
-
it('
|
|
152
|
+
it('does not show disconnected devices', () => {
|
|
153
153
|
render(
|
|
154
154
|
<DeviceSelector
|
|
155
155
|
deviceListing={{
|
|
@@ -164,7 +164,7 @@ describe('DeviceSelector', () => {
|
|
|
164
164
|
expect(screen.queryByText(DEVICE_SERIAL_NUMBER)).toBeNull();
|
|
165
165
|
});
|
|
166
166
|
|
|
167
|
-
it('
|
|
167
|
+
it('shows more device info when selecting the expand button', () => {
|
|
168
168
|
render(
|
|
169
169
|
<DeviceSelector
|
|
170
170
|
deviceListing={{
|
|
@@ -181,7 +181,7 @@ describe('DeviceSelector', () => {
|
|
|
181
181
|
expect(screen.getAllByText(/COM/)).toHaveLength(2);
|
|
182
182
|
});
|
|
183
183
|
|
|
184
|
-
it('
|
|
184
|
+
it('allows selecting a device', async () => {
|
|
185
185
|
render(
|
|
186
186
|
<DeviceSelector
|
|
187
187
|
deviceListing={{
|
|
@@ -203,7 +203,7 @@ describe('DeviceSelector', () => {
|
|
|
203
203
|
expect(screen.getAllByText(DEVICE_SERIAL_NUMBER)).toHaveLength(2);
|
|
204
204
|
});
|
|
205
205
|
|
|
206
|
-
it('
|
|
206
|
+
it('allows disconnecting a device', async () => {
|
|
207
207
|
render(
|
|
208
208
|
<DeviceSelector
|
|
209
209
|
deviceListing={{
|
|
@@ -223,7 +223,7 @@ describe('DeviceSelector', () => {
|
|
|
223
223
|
expect(screen.getByText('Select device')).toBeInTheDocument();
|
|
224
224
|
});
|
|
225
225
|
|
|
226
|
-
it('
|
|
226
|
+
it('allows selecting a device when custom devices are enabled and no valid firmware is defined', async () => {
|
|
227
227
|
render(
|
|
228
228
|
<DeviceSelector
|
|
229
229
|
deviceListing={{
|
|
@@ -259,7 +259,7 @@ describe('DeviceSelector', () => {
|
|
|
259
259
|
expect(screen.getAllByText(DEVICE_SERIAL_NUMBER)).toHaveLength(2);
|
|
260
260
|
});
|
|
261
261
|
|
|
262
|
-
it('
|
|
262
|
+
it('allows deselecting a device when custom devices are disabled and no valid firmware is defined', async () => {
|
|
263
263
|
render(
|
|
264
264
|
<DeviceSelector
|
|
265
265
|
deviceListing={{
|
|
@@ -295,7 +295,7 @@ describe('DeviceSelector', () => {
|
|
|
295
295
|
await screen.findByText('Select device');
|
|
296
296
|
});
|
|
297
297
|
|
|
298
|
-
it('
|
|
298
|
+
it('shows firmware prompt when a valid firmware is defined', async () => {
|
|
299
299
|
render(
|
|
300
300
|
<DeviceSelector
|
|
301
301
|
deviceListing={{
|
|
@@ -317,7 +317,7 @@ describe('DeviceSelector', () => {
|
|
|
317
317
|
);
|
|
318
318
|
});
|
|
319
319
|
|
|
320
|
-
it('
|
|
320
|
+
it('selects a device when cancelling firmware prompt', async () => {
|
|
321
321
|
render(
|
|
322
322
|
<DeviceSelector
|
|
323
323
|
deviceListing={{
|
|
@@ -28,18 +28,17 @@ describe('Dialog', () => {
|
|
|
28
28
|
</Dialog>
|
|
29
29
|
);
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
it('is rendered when visible', () => {
|
|
32
32
|
render(dialog());
|
|
33
33
|
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
|
34
|
-
test;
|
|
35
34
|
});
|
|
36
35
|
|
|
37
|
-
|
|
36
|
+
it('is not rendered when not visible', () => {
|
|
38
37
|
render(dialog(false));
|
|
39
38
|
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
|
40
39
|
});
|
|
41
40
|
|
|
42
|
-
|
|
41
|
+
it('shows the expected content', () => {
|
|
43
42
|
render(dialog());
|
|
44
43
|
|
|
45
44
|
expect(screen.getByText('Test Title')).toBeInTheDocument();
|
|
@@ -55,7 +54,7 @@ describe('InfoDialog creator', () => {
|
|
|
55
54
|
</InfoDialog>
|
|
56
55
|
);
|
|
57
56
|
|
|
58
|
-
|
|
57
|
+
it('shows the expected content', () => {
|
|
59
58
|
render(dialog());
|
|
60
59
|
|
|
61
60
|
expect(screen.getByText('Info')).toBeInTheDocument();
|
|
@@ -63,7 +62,7 @@ describe('InfoDialog creator', () => {
|
|
|
63
62
|
expect(screen.getByText('Close')).toBeInTheDocument();
|
|
64
63
|
});
|
|
65
64
|
|
|
66
|
-
|
|
65
|
+
it('invokes the expected action', () => {
|
|
67
66
|
render(dialog());
|
|
68
67
|
|
|
69
68
|
const closeButton = screen.getByText('Close');
|
|
@@ -80,7 +79,7 @@ describe('ErrorDialog creator', () => {
|
|
|
80
79
|
</ErrorDialog>
|
|
81
80
|
);
|
|
82
81
|
|
|
83
|
-
|
|
82
|
+
it('shows the expected content', () => {
|
|
84
83
|
render(dialog());
|
|
85
84
|
|
|
86
85
|
expect(screen.getByText('Error')).toBeInTheDocument();
|
|
@@ -88,7 +87,7 @@ describe('ErrorDialog creator', () => {
|
|
|
88
87
|
expect(screen.getByText('Close')).toBeInTheDocument();
|
|
89
88
|
});
|
|
90
89
|
|
|
91
|
-
|
|
90
|
+
it('invokes the expected action', () => {
|
|
92
91
|
render(dialog());
|
|
93
92
|
|
|
94
93
|
const closeButton = screen.getByText('Close');
|
|
@@ -111,7 +110,7 @@ describe('ConfirmationDialog creator', () => {
|
|
|
111
110
|
</ConfirmationDialog>
|
|
112
111
|
);
|
|
113
112
|
|
|
114
|
-
|
|
113
|
+
it('shows the expected content', () => {
|
|
115
114
|
render(dialog());
|
|
116
115
|
|
|
117
116
|
expect(screen.getByText('Confirm')).toBeInTheDocument();
|
|
@@ -121,7 +120,7 @@ describe('ConfirmationDialog creator', () => {
|
|
|
121
120
|
expect(screen.getByText('Cancel')).toBeInTheDocument();
|
|
122
121
|
});
|
|
123
122
|
|
|
124
|
-
|
|
123
|
+
it('invokes the expected action', () => {
|
|
125
124
|
render(dialog());
|
|
126
125
|
|
|
127
126
|
fireEvent.click(screen.getByText('Optional'));
|
|
@@ -22,7 +22,7 @@ const items = [
|
|
|
22
22
|
];
|
|
23
23
|
|
|
24
24
|
describe('Dropdown', () => {
|
|
25
|
-
it('
|
|
25
|
+
it('shows a list of items', () => {
|
|
26
26
|
render(
|
|
27
27
|
<Dropdown
|
|
28
28
|
items={items}
|
|
@@ -34,7 +34,7 @@ describe('Dropdown', () => {
|
|
|
34
34
|
expect(screen.getByText('Bar')).toBeInTheDocument();
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
it('calls onSelect
|
|
37
|
+
it('calls onSelect', () => {
|
|
38
38
|
const onSelect = jest.fn();
|
|
39
39
|
const item = items[1];
|
|
40
40
|
render(
|
|
@@ -49,7 +49,7 @@ describe('Dropdown', () => {
|
|
|
49
49
|
expect(onSelect).toHaveBeenCalledWith(item);
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
-
it('correct item
|
|
52
|
+
it('selects the correct item', () => {
|
|
53
53
|
render(
|
|
54
54
|
<Dropdown
|
|
55
55
|
items={items}
|
|
@@ -28,6 +28,7 @@ export type DropdownProps<T> = {
|
|
|
28
28
|
selectedItem: DropdownItem<T>;
|
|
29
29
|
numItemsBeforeScroll?: number;
|
|
30
30
|
className?: string;
|
|
31
|
+
size?: 'sm' | 'md';
|
|
31
32
|
};
|
|
32
33
|
|
|
33
34
|
export default <T,>({
|
|
@@ -42,6 +43,7 @@ export default <T,>({
|
|
|
42
43
|
selectedItem,
|
|
43
44
|
numItemsBeforeScroll = 0,
|
|
44
45
|
className = '',
|
|
46
|
+
size = 'md',
|
|
45
47
|
}: DropdownProps<T>) => {
|
|
46
48
|
const [isActive, setIsActive] = useState(false);
|
|
47
49
|
|
|
@@ -74,7 +76,12 @@ export default <T,>({
|
|
|
74
76
|
minWidth ? '' : 'tw-w-full',
|
|
75
77
|
transparentButtonBg
|
|
76
78
|
? 'tw-bg-transparent'
|
|
77
|
-
:
|
|
79
|
+
: classNames(
|
|
80
|
+
'tw-bg-gray-700 tw-text-white',
|
|
81
|
+
size === 'sm'
|
|
82
|
+
? 'tw-h-6 tw-pl-2 tw-pr-1 tw-text-2xs'
|
|
83
|
+
: 'tw-h-8 tw-px-2'
|
|
84
|
+
)
|
|
78
85
|
)}
|
|
79
86
|
onClick={() => setIsActive(!isActive)}
|
|
80
87
|
disabled={disabled}
|
|
@@ -85,8 +92,9 @@ export default <T,>({
|
|
|
85
92
|
: selectedItem.label}
|
|
86
93
|
</span>
|
|
87
94
|
<span
|
|
88
|
-
className={`mdi mdi-chevron-down
|
|
89
|
-
isActive && 'tw-rotate-180'
|
|
95
|
+
className={`mdi mdi-chevron-down ${classNames(
|
|
96
|
+
isActive && 'tw-rotate-180',
|
|
97
|
+
size === 'sm' ? 'tw-text-base' : 'tw-text-lg'
|
|
90
98
|
)}`}
|
|
91
99
|
/>
|
|
92
100
|
</button>
|
|
@@ -116,7 +124,10 @@ export default <T,>({
|
|
|
116
124
|
{items.map(item => (
|
|
117
125
|
<button
|
|
118
126
|
type="button"
|
|
119
|
-
className=
|
|
127
|
+
className={classNames(
|
|
128
|
+
'tw-bg-transparent tw-clear-both tw-block tw-h-6 tw-w-full tw-whitespace-nowrap tw-border-0 tw-px-2 tw-py-1 tw-text-left tw-font-normal tw-text-white hover:tw-bg-gray-600 focus:tw-bg-gray-600',
|
|
129
|
+
size === 'sm' && 'tw-text-2xs'
|
|
130
|
+
)}
|
|
120
131
|
key={JSON.stringify(item.value)}
|
|
121
132
|
onClick={() => onClickItem(item)}
|
|
122
133
|
>
|
|
@@ -10,40 +10,39 @@ import {
|
|
|
10
10
|
getSelectedDropdownItem,
|
|
11
11
|
} from './DropdownHelpers';
|
|
12
12
|
|
|
13
|
+
const itemList = [
|
|
14
|
+
{ label: 'foo label', value: 'foo' },
|
|
15
|
+
{ label: 'bar label', value: 'bar' },
|
|
16
|
+
];
|
|
17
|
+
|
|
13
18
|
describe('getSelectedDropdownItem', () => {
|
|
19
|
+
it('returns the item with the correct value', () => {
|
|
20
|
+
expect(getSelectedDropdownItem(itemList, 'bar')).toBe(itemList[1]);
|
|
21
|
+
});
|
|
22
|
+
|
|
14
23
|
it('returns the first item if value is undefined', () => {
|
|
15
|
-
const itemList = [{ label: 'foo', value: 'foo' }];
|
|
16
24
|
expect(getSelectedDropdownItem(itemList, undefined)).toBe(itemList[0]);
|
|
17
25
|
});
|
|
18
26
|
|
|
19
27
|
it('returns the first item if value is not found', () => {
|
|
20
|
-
|
|
21
|
-
expect(getSelectedDropdownItem(itemList, 'bar')).toBe(itemList[0]);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('returns the item with the correct value', () => {
|
|
25
|
-
const itemList = [
|
|
26
|
-
{ label: 'foo', value: 'foo' },
|
|
27
|
-
{ label: 'bar', value: 'bar' },
|
|
28
|
-
];
|
|
29
|
-
expect(getSelectedDropdownItem(itemList, 'bar')).toBe(itemList[1]);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('returns the item with the correct value when value is a boolean', () => {
|
|
33
|
-
const itemList = [
|
|
34
|
-
{ label: 'on', value: 'on' },
|
|
35
|
-
{ label: 'off', value: 'off' },
|
|
36
|
-
];
|
|
37
|
-
expect(getSelectedDropdownItem(itemList, true)).toBe(itemList[0]);
|
|
28
|
+
expect(getSelectedDropdownItem(itemList, 'unknown')).toBe(itemList[0]);
|
|
38
29
|
});
|
|
39
30
|
|
|
40
31
|
it('returns the notFound item if value is not found', () => {
|
|
41
|
-
const itemList = [{ label: 'foo', value: 'foo' }];
|
|
42
32
|
const notFound = { label: 'not found', value: 'not found' };
|
|
43
|
-
expect(getSelectedDropdownItem(itemList, '
|
|
33
|
+
expect(getSelectedDropdownItem(itemList, 'unknown', notFound)).toBe(
|
|
44
34
|
notFound
|
|
45
35
|
);
|
|
46
36
|
});
|
|
37
|
+
|
|
38
|
+
it('handles booleans as the strings `on` and `off`', () => {
|
|
39
|
+
const booleanList = [
|
|
40
|
+
{ label: 'on label', value: 'on' },
|
|
41
|
+
{ label: 'off label', value: 'off' },
|
|
42
|
+
];
|
|
43
|
+
expect(getSelectedDropdownItem(booleanList, true).value).toBe('on');
|
|
44
|
+
expect(getSelectedDropdownItem(booleanList, false).value).toBe('off');
|
|
45
|
+
});
|
|
47
46
|
});
|
|
48
47
|
|
|
49
48
|
describe('convertToDropDownItems', () => {
|