Skip to content

Commit ab143c8

Browse files
authored
feat(header): add fast highlight + network lock for duplicated package (#537)
1 parent 75881bc commit ab143c8

File tree

8 files changed

+115
-6
lines changed

8 files changed

+115
-6
lines changed

public/components/package/header/header.css

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@ div.package-header>.package-name>.info-menu>a {
6666
/**
6767
* DESC
6868
*/
69+
70+
div.package-header>.package-description{
71+
display: flex;
72+
justify-content: space-between;
73+
}
74+
6975
div.package-header>.description {
7076
width: 100%;
7177
color: #FFF;
@@ -74,6 +80,15 @@ div.package-header>.description {
7480
margin-top: 7px;
7581
}
7682

83+
div.package-header>.package-description>.has-duplicate {
84+
border: none;
85+
background: transparent;
86+
transform: translateY(-4px);
87+
font-size: 18px;
88+
cursor: pointer;
89+
padding: 0;
90+
}
91+
7792
/**
7893
* FLAGS
7994
*/

public/components/package/header/header.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Import Third-party Dependencies
2-
import { getFlagsEmojisInlined } from "@nodesecure/vis-network";
2+
import { getFlagsEmojisInlined, FLAGS_EMOJIS } from "@nodesecure/vis-network";
33

44
// Import Internal Dependencies
55
import * as utils from "../../../common/utils.js";
@@ -109,6 +109,11 @@ export class PackageHeader {
109109
flagsDomElement.appendChild(flagFragment);
110110
}
111111

112+
// Has Duplicate Button
113+
if (this.#hasDuplicate()) {
114+
this.#renderHasDuplicateBtn(clone);
115+
}
116+
112117
return links;
113118
}
114119

@@ -244,6 +249,29 @@ export class PackageHeader {
244249

245250
return fragment;
246251
}
252+
253+
#hasDuplicate() {
254+
return this.package.dependencyVersion.flags.some((title) => title === "hasDuplicate") &&
255+
!window.settings.config.ignore.warnings.has("hasDuplicate") &&
256+
"isDuplicated" in FLAGS_EMOJIS;
257+
}
258+
259+
#renderHasDuplicateBtn(clone) {
260+
const hasDuplicateBtn = utils.createDOMElement("button",
261+
{ classList: ["has-duplicate"], text: FLAGS_EMOJIS.isDuplicated });
262+
263+
const packagesList = this.nsn.secureDataSet.findPackagesByName(this.package.dependencyVersion.name)
264+
.map(({ name, version }) => `${name}@${version}`);
265+
266+
hasDuplicateBtn.addEventListener("click", () => {
267+
const nodeIds = [...this.nsn.findNodeIds(new Set(packagesList))];
268+
this.nsn.highlightMultipleNodes(nodeIds);
269+
window.locker.lock();
270+
});
271+
272+
const packageDescDiv = clone.querySelector(".package-description");
273+
packageDescDiv.appendChild(hasDuplicateBtn);
274+
}
247275
}
248276

249277
function createFlagInfoBulle(text, description) {

public/components/package/package.html

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@
66
<p class="version"></p>
77
<button class="info"></button>
88
</div>
9-
<p class="description"></p>
9+
<div class="package-description">
10+
<p class="description"></p>
11+
</div>
1012
<ul class="flags"></ul>
1113
<div class="links"></div>
1214
</div>

workspaces/vis-network/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,14 @@
11
// Import Internal Dependencies
22
import NodeSecureDataSet from "./src/dataset.js";
33
import NodeSecureNetwork, { NETWORK_OPTIONS } from "./src/network.js";
4-
import { getJSON, getFlagsEmojisInlined } from "./src/utils.js";
4+
import { getJSON, getFlagsEmojisInlined, FLAGS_EMOJIS } from "./src/utils.js";
55

66
export * from "./src/constants.js";
77

88
export {
99
getJSON,
1010
getFlagsEmojisInlined,
11+
FLAGS_EMOJIS,
1112
NodeSecureDataSet,
1213
NodeSecureNetwork,
1314
NETWORK_OPTIONS

workspaces/vis-network/src/dataset.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -228,4 +228,8 @@ export default class NodeSecureDataSet extends EventTarget {
228228
isHighlighted(contact) {
229229
return this.#highligthedContacts.names.has(contact.name) || this.#highligthedContacts.emails.has(contact.email);
230230
}
231+
232+
findPackagesByName(name) {
233+
return this.packages.filter((pkg) => pkg.name === name);
234+
}
231235
}

workspaces/vis-network/src/utils.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { getManifestEmoji } from "@nodesecure/flags/web";
55
import * as CONSTANTS from "./constants.js";
66

77
// CONSTANTS
8-
const kFlagsEmojis = Object.fromEntries(getManifestEmoji());
8+
export const FLAGS_EMOJIS = Object.fromEntries(getManifestEmoji());
99

1010
export async function getJSON(path, customHeaders = Object.create(null)) {
1111
const headers = {
@@ -73,7 +73,7 @@ export function getFlagsEmojisInlined(
7373
}
7474

7575
// FIX: when scanner resolve to flags ^3.x
76-
const emoji = kFlagsEmojis[title === "hasDuplicate" ? "isDuplicated" : title];
76+
const emoji = FLAGS_EMOJIS[title === "hasDuplicate" ? "isDuplicated" : title];
7777

7878
return emoji ? [emoji] : [];
7979
})

workspaces/vis-network/test/dataset-payload.json

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,29 @@
6464
],
6565
"name": "pkg2",
6666
"version": "1.0.3"
67+
},
68+
"1.0.4": {
69+
"usedBy": {
70+
"pkg3": "3.4.0"
71+
},
72+
"flags": [],
73+
"size": 100,
74+
"author": {},
75+
"warnings": [],
76+
"composition": {
77+
"extensions": [
78+
".md",
79+
".js",
80+
"",
81+
".json"
82+
]
83+
},
84+
"licenses": [],
85+
"uniqueLicenseIds": [
86+
"Unlicense"
87+
],
88+
"name": "pkg2",
89+
"version": "1.0.4"
6790
}
6891
}
6992
},
@@ -156,4 +179,4 @@
156179
"warning_02"
157180
],
158181
"vulnerabilityStrategy": "npm"
159-
}
182+
}

workspaces/vis-network/test/dataset.test.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,3 +97,39 @@ test("NodeSecureDataSet.build", () => {
9797
assert.equal(builtData.nodes.length, 2, "should have 2 nodes");
9898
assert.equal(builtData.edges.length, 3, "should have 3 edges");
9999
});
100+
101+
test("NodeSecureDataSet.findPackagesByName should have no packages when no name matches", async() => {
102+
const nsDataSet = new NodeSecureDataSet();
103+
await nsDataSet.init(dataSetPayload);
104+
105+
assert.equal(nsDataSet.findPackagesByName("unknown").length, 0, "should have no packages");
106+
});
107+
108+
test("NodeSecureDataSet.findPackagesByName should have packages when name matches", async() => {
109+
const nsDataSet = new NodeSecureDataSet();
110+
await nsDataSet.init(dataSetPayload);
111+
const packages = nsDataSet.findPackagesByName("pkg2");
112+
113+
const expectedPackages = [
114+
{
115+
id: undefined,
116+
name: "pkg2",
117+
version: "1.0.3",
118+
hasWarnings: false,
119+
flags: "",
120+
links: undefined,
121+
isFriendly: 0
122+
},
123+
{
124+
id: undefined,
125+
name: "pkg2",
126+
version: "1.0.4",
127+
hasWarnings: false,
128+
flags: "",
129+
links: undefined,
130+
isFriendly: 0
131+
}
132+
];
133+
134+
assert.deepEqual(packages, expectedPackages, "should all versions by name");
135+
});

0 commit comments

Comments
 (0)