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