Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion i18n/english.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ const ui = {
section_extensions: "File extensions",
section_builtins: "Node.js core modules",
section_authors: "Authors",
section_dep: "Packages depending on",
hint_size: "e.g. >50kb, 10kb..200kb",
hint_version: "e.g. ^1.0.0, >=2.0.0",
empty: "No results found",
Expand All @@ -323,7 +324,8 @@ const ui = {
ext: "file extension",
builtin: "node.js module",
size: "e.g. >50kb",
highlighted: "all"
highlighted: "all",
dep: "package name"
}
},
legend: {
Expand Down
4 changes: 3 additions & 1 deletion i18n/french.js
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ const ui = {
section_extensions: "Extensions de fichiers",
section_builtins: "Modules Node.js natifs",
section_authors: "Auteurs",
section_dep: "Packages dépendant de",
hint_size: "ex. >50kb, 10kb..200kb",
hint_version: "ex. ^1.0.0, >=2.0.0",
empty: "Aucun résultat trouvé",
Expand All @@ -323,7 +324,8 @@ const ui = {
ext: "extension de fichier",
builtin: "module node.js",
size: "ex. >50kb",
highlighted: "all"
highlighted: "all",
dep: "nom du package"
}
},
legend: {
Expand Down
3 changes: 2 additions & 1 deletion public/components/command-palette/command-palette-panels.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ const kListTitleKeys = {
license: "section_licenses",
ext: "section_extensions",
builtin: "section_builtins",
author: "section_authors"
author: "section_authors",
dep: "section_dep"
};

/**
Expand Down
76 changes: 74 additions & 2 deletions public/components/command-palette/filters.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,18 @@ export const VERSION_PRESETS = [
{ label: "≥ 1.0", value: ">=1.0.0" },
{ label: "< 1.0", value: "<1.0.0" }
];
export const FILTERS_NAME = new Set(["package", "version", "flag", "license", "author", "ext", "builtin", "size", "highlighted"]);
export const FILTERS_NAME = new Set([
"package",
"version",
"flag",
"license",
"author",
"ext",
"builtin",
"size",
"highlighted",
"dep"
]);
export const PRESETS = [
{ id: "has_vulnerabilities", filter: "flag", value: "hasVulnerabilities" },
{ id: "has_scripts", filter: "flag", value: "hasScript" },
Expand All @@ -29,7 +40,7 @@ export const PRESETS = [
{ id: "large", filter: "size", value: ">100kb" }
];
// Filters that use a searchable text-based list (not a rich visual panel)
export const FILTER_HAS_HELPERS = new Set(["license", "ext", "builtin", "author"]);
export const FILTER_HAS_HELPERS = new Set(["license", "ext", "builtin", "author", "dep"]);
// Filters where the mode persists after selection (multi-select)
export const FILTER_MULTI_SELECT = new Set(["flag"]);
// Filters that auto-confirm immediately on selection (no text input needed)
Expand Down Expand Up @@ -60,6 +71,18 @@ export function getFlagCounts(linker) {
* @returns {Map<string, number>}
*/
export function getFilterValueCounts(linker, filterName) {
if (filterName === "dep") {
const counts = new Map();
for (const opt of linker.values()) {
const dependentCount = Object.keys(opt.usedBy).length;
if (dependentCount > 0) {
counts.set(opt.name, (counts.get(opt.name) ?? 0) + dependentCount);
}
}

return counts;
}

const counts = new Map();
for (const opt of linker.values()) {
for (const value of getValuesForCount(opt, filterName)) {
Expand Down Expand Up @@ -155,6 +178,16 @@ export function getHelperValues(linker, filterName) {
return { display: name, value: name };
});
}
case "dep": {
const items = new Set();
for (const { name } of linker.values()) {
items.add(name);
}

return [...items].sort().map((name) => {
return { display: name, value: name };
});
}
default:
return [];
}
Expand All @@ -169,6 +202,10 @@ export function getHelperValues(linker, filterName) {
* @returns {Set<string>}
*/
export function computeMatches(linker, filterName, inputValue) {
if (filterName === "dep") {
return computeDepMatches(linker, inputValue);
}

const matchingIds = new Set();

for (const [id, opt] of linker) {
Expand All @@ -180,6 +217,41 @@ export function computeMatches(linker, filterName, inputValue) {
return matchingIds;
}

/**
* Collect packages that depend on package matching inputValue
*
* @param {Map<number, object>} linker
* @param {string} inputValue
* @returns {Set<string>}
*/
function computeDepMatches(linker, inputValue) {
const matchingIds = new Set();

try {
const regex = new RegExp(inputValue, "i");

const dependentNames = new Set();
for (const opt of linker.values()) {
if (regex.test(opt.name)) {
for (const dependency of Object.keys(opt.usedBy)) {
dependentNames.add(dependency);
}
}
}

for (const [id, opt] of linker) {
if (dependentNames.has(opt.name)) {
matchingIds.add(String(id));
}
}
}
catch {
// invalid regex
}

return matchingIds;
}

function matchesFilter(opt, filterName, inputValue) {
switch (filterName) {
case "package": {
Expand Down
82 changes: 82 additions & 0 deletions test/e2e/command-palette.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,88 @@ test.describe("[command-palette] presets and actions", () => {
});
});

test.describe("[command-palette] dep filter", () => {
let i18n;

test.beforeEach(async({ page }) => {
await page.goto("/");
await page.waitForSelector(`[data-menu="network--view"].active`);

i18n = await page.evaluate(() => {
const lang = document.getElementById("lang").dataset.lang;
const activeLang = lang in window.i18n ? lang : "english";

return window.i18n[activeLang].search_command;
});

await page.locator("body").click();
await page.keyboard.press("Control+k");

await expect(page.locator(".backdrop")).toBeVisible();
});

test("dep appears in the filter hint list", async({ page }) => {
const filterRow = page
.locator(".helper-item")
.filter({ hasText: "dep:" });

await expect(filterRow).toBeVisible();
await expect(filterRow).toContainText(i18n.filter_hints.dep);
});

test("typing dep: activates the filter and shows the dep panel", async({ page }) => {
await page.locator("#cmd-input").fill("dep:");

await expect(
page
.locator(".section-title").filter({ hasText: i18n.section_dep })).toBeVisible();
});

test("dep list panel shows all package names as helpers", async({ page }) => {
await page.locator("#cmd-input").fill("dep:");

await expect(page.locator(".list-item").filter({ hasText: "debug" })).toBeVisible();
await expect(page.locator(".list-item").filter({ hasText: "ms" })).toBeVisible();
});

test("typing dep:ms and pressing Enter adds a chip and shows debug as result", async({ page }) => {
await page.locator("#cmd-input").fill("dep:ms");
await page.keyboard.press("Enter");

await expect(page.locator("search-chip")).toBeVisible();
await expect(page.locator(".result-item")).toHaveCount(1);
await expect(page.locator(".result-item")).toContainText("debug");
});

test("typing dep:debug and pressing Enter shows empty results", async({ page }) => {
await page.locator("#cmd-input").fill("dep:debug");
await page.keyboard.press("Enter");

await expect(page.locator("search-chip")).toBeVisible();
await expect(page.locator(".dialog .empty-state")).toHaveText(i18n.empty_after_filter);
});

test("dep chip label shows filter and value", async({ page }) => {
await page.locator("#cmd-input").fill("dep:ms");
await page.keyboard.press("Enter");

const chip = page.locator("search-chip");
await expect(chip).toHaveAttribute("filter", "dep");
await expect(chip).toHaveAttribute("value", "ms");
});

test("removing the dep chip clears the results", async({ page }) => {
await page.locator("#cmd-input").fill("dep:ms");
await page.keyboard.press("Enter");

await expect(page.locator("search-chip")).toBeVisible();

await page.keyboard.press("Backspace");

await expect(page.locator("search-chip")).not.toBeVisible();
});
});

test.describe("[command-palette] ignore flags and warnings", () => {
let i18n;

Expand Down
Loading
Loading