mirror of
https://github.com/home-assistant/frontend.git
synced 2025-04-19 19:07:23 +00:00
Ignore diacritics (accents) in search (#21150)
* Ignore diacritics in search * Rename variable
This commit is contained in:
parent
1acada625f
commit
f42a9ac070
@ -1,5 +1,6 @@
|
||||
import Fuse from "fuse.js";
|
||||
import type { IFuseOptions } from "fuse.js";
|
||||
import Fuse from "fuse.js";
|
||||
import { stripDiacritics } from "../../../src/common/string/strip-diacritics";
|
||||
import { StoreAddon } from "../../../src/data/supervisor/store";
|
||||
|
||||
export function filterAndSort(addons: StoreAddon[], filter: string) {
|
||||
@ -8,7 +9,8 @@ export function filterAndSort(addons: StoreAddon[], filter: string) {
|
||||
isCaseSensitive: false,
|
||||
minMatchCharLength: Math.min(filter.length, 2),
|
||||
threshold: 0.2,
|
||||
getFn: (obj, path) => stripDiacritics(Fuse.config.getFn(obj, path)),
|
||||
};
|
||||
const fuse = new Fuse(addons, options);
|
||||
return fuse.search(filter).map((result) => result.item);
|
||||
return fuse.search(stripDiacritics(filter)).map((result) => result.item);
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { stripDiacritics } from "../strip-diacritics";
|
||||
import { fuzzyScore } from "./filter";
|
||||
|
||||
/**
|
||||
@ -19,10 +20,10 @@ export const fuzzySequentialMatch = (
|
||||
for (const word of item.strings) {
|
||||
const scores = fuzzyScore(
|
||||
filter,
|
||||
filter.toLowerCase(),
|
||||
stripDiacritics(filter.toLowerCase()),
|
||||
0,
|
||||
word,
|
||||
word.toLowerCase(),
|
||||
stripDiacritics(word.toLowerCase()),
|
||||
0,
|
||||
true
|
||||
);
|
||||
|
2
src/common/string/strip-diacritics.ts
Normal file
2
src/common/string/strip-diacritics.ts
Normal file
@ -0,0 +1,2 @@
|
||||
export const stripDiacritics = (str) =>
|
||||
str.normalize("NFD").replace(/[\u0300-\u036F]/g, "");
|
@ -1,5 +1,6 @@
|
||||
import { expose } from "comlink";
|
||||
import { stringCompare } from "../../common/string/compare";
|
||||
import { stripDiacritics } from "../../common/string/strip-diacritics";
|
||||
import type {
|
||||
ClonedDataTableColumnData,
|
||||
DataTableRowData,
|
||||
@ -12,20 +13,18 @@ const filterData = (
|
||||
columns: SortableColumnContainer,
|
||||
filter: string
|
||||
) => {
|
||||
filter = filter.toUpperCase();
|
||||
filter = stripDiacritics(filter.toLowerCase());
|
||||
return data.filter((row) =>
|
||||
Object.entries(columns).some((columnEntry) => {
|
||||
const [key, column] = columnEntry;
|
||||
if (column.filterable) {
|
||||
if (
|
||||
String(
|
||||
column.filterKey
|
||||
? row[column.valueColumn || key][column.filterKey]
|
||||
: row[column.valueColumn || key]
|
||||
)
|
||||
.toUpperCase()
|
||||
.includes(filter)
|
||||
) {
|
||||
const value = String(
|
||||
column.filterKey
|
||||
? row[column.valueColumn || key][column.filterKey]
|
||||
: row[column.valueColumn || key]
|
||||
);
|
||||
|
||||
if (stripDiacritics(value).toLowerCase().includes(filter)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ import {
|
||||
AddAutomationElementDialogParams,
|
||||
PASTE_VALUE,
|
||||
} from "./show-add-automation-element-dialog";
|
||||
import { stripDiacritics } from "../../../common/string/strip-diacritics";
|
||||
|
||||
const TYPES = {
|
||||
trigger: { groups: TRIGGER_GROUPS, icons: TRIGGER_ICONS },
|
||||
@ -208,9 +209,10 @@ class DialogAddAutomationElement extends LitElement implements HassDialog {
|
||||
isCaseSensitive: false,
|
||||
minMatchCharLength: Math.min(filter.length, 2),
|
||||
threshold: 0.2,
|
||||
getFn: (obj, path) => stripDiacritics(Fuse.config.getFn(obj, path)),
|
||||
};
|
||||
const fuse = new Fuse(items, options);
|
||||
return fuse.search(filter).map((result) => result.item);
|
||||
return fuse.search(stripDiacritics(filter)).map((result) => result.item);
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -55,6 +55,7 @@ import {
|
||||
showYamlIntegrationDialog,
|
||||
} from "./show-add-integration-dialog";
|
||||
import { getConfigEntries } from "../../../data/config_entries";
|
||||
import { stripDiacritics } from "../../../common/string/strip-diacritics";
|
||||
|
||||
export interface IntegrationListItem {
|
||||
name: string;
|
||||
@ -255,6 +256,7 @@ class AddIntegrationDialog extends LitElement {
|
||||
isCaseSensitive: false,
|
||||
minMatchCharLength: Math.min(filter.length, 2),
|
||||
threshold: 0.2,
|
||||
getFn: (obj, path) => stripDiacritics(Fuse.config.getFn(obj, path)),
|
||||
};
|
||||
const helpers = Object.entries(h).map(([domain, integration]) => ({
|
||||
domain,
|
||||
@ -264,15 +266,16 @@ class AddIntegrationDialog extends LitElement {
|
||||
is_built_in: integration.is_built_in !== false,
|
||||
cloud: integration.iot_class?.startsWith("cloud_"),
|
||||
}));
|
||||
const normalizedFilter = stripDiacritics(filter);
|
||||
return [
|
||||
...new Fuse(integrations, options)
|
||||
.search(filter)
|
||||
.search(normalizedFilter)
|
||||
.map((result) => result.item),
|
||||
...new Fuse(yamlIntegrations, options)
|
||||
.search(filter)
|
||||
.search(normalizedFilter)
|
||||
.map((result) => result.item),
|
||||
...new Fuse(helpers, options)
|
||||
.search(filter)
|
||||
.search(normalizedFilter)
|
||||
.map((result) => result.item),
|
||||
];
|
||||
}
|
||||
|
@ -71,6 +71,7 @@ import { showAddIntegrationDialog } from "./show-add-integration-dialog";
|
||||
import "./ha-disabled-config-entry-card";
|
||||
import { caseInsensitiveStringCompare } from "../../../common/string/compare";
|
||||
import "../../../components/search-input-outlined";
|
||||
import { stripDiacritics } from "../../../common/string/strip-diacritics";
|
||||
|
||||
export interface ConfigEntryExtended extends ConfigEntry {
|
||||
localized_domain_name?: string;
|
||||
@ -208,9 +209,12 @@ class HaConfigIntegrationsDashboard extends SubscribeMixin(LitElement) {
|
||||
isCaseSensitive: false,
|
||||
minMatchCharLength: Math.min(filter.length, 2),
|
||||
threshold: 0.2,
|
||||
getFn: (obj, path) => stripDiacritics(Fuse.config.getFn(obj, path)),
|
||||
};
|
||||
const fuse = new Fuse(configEntriesInProgress, options);
|
||||
filteredEntries = fuse.search(filter).map((result) => result.item);
|
||||
filteredEntries = fuse
|
||||
.search(stripDiacritics(filter))
|
||||
.map((result) => result.item);
|
||||
} else {
|
||||
filteredEntries = configEntriesInProgress;
|
||||
}
|
||||
|
@ -16,6 +16,7 @@ import memoizeOne from "memoize-one";
|
||||
import { storage } from "../../../../common/decorators/storage";
|
||||
import { fireEvent } from "../../../../common/dom/fire_event";
|
||||
import { stringCompare } from "../../../../common/string/compare";
|
||||
import { stripDiacritics } from "../../../../common/string/strip-diacritics";
|
||||
import "../../../../components/ha-circular-progress";
|
||||
import "../../../../components/search-input";
|
||||
import { isUnavailableState } from "../../../../data/entity";
|
||||
@ -86,9 +87,10 @@ export class HuiCardPicker extends LitElement {
|
||||
isCaseSensitive: false,
|
||||
minMatchCharLength: Math.min(filter.length, 2),
|
||||
threshold: 0.2,
|
||||
getFn: (obj, path) => stripDiacritics(Fuse.config.getFn(obj, path)),
|
||||
};
|
||||
const fuse = new Fuse(cards, options);
|
||||
cards = fuse.search(filter).map((result) => result.item);
|
||||
cards = fuse.search(stripDiacritics(filter)).map((result) => result.item);
|
||||
return cardElements.filter((cardElement: CardElement) =>
|
||||
cards.includes(cardElement.card)
|
||||
);
|
||||
|
Loading…
x
Reference in New Issue
Block a user