diff --git a/hassio/src/addon-store/hassio-addon-repository.ts b/hassio/src/addon-store/hassio-addon-repository.ts
index dd5a56ea46..5427ae8fe1 100644
--- a/hassio/src/addon-store/hassio-addon-repository.ts
+++ b/hassio/src/addon-store/hassio-addon-repository.ts
@@ -7,6 +7,7 @@ import {
CSSResultArray,
} from "lit-element";
import "@polymer/paper-card/paper-card";
+import memoizeOne from "memoize-one";
import "../components/hassio-card-content";
import { hassioStyle } from "../resources/hassio-style";
@@ -16,14 +17,40 @@ import {
HassioAddonRepository,
} from "../../../src/data/hassio";
import { navigate } from "../../../src/common/navigate";
+import { filterAndSort } from "../components/hassio-filter-addons";
class HassioAddonRepositoryEl extends LitElement {
@property() public hass!: HomeAssistant;
@property() public repo!: HassioAddonRepository;
@property() public addons!: HassioAddonInfo[];
+ @property() public filter!: string;
+
+ private _getAddons = memoizeOne(
+ (addons: HassioAddonInfo[], filter?: string) => {
+ if (filter) {
+ return filterAndSort(addons, filter);
+ }
+ return addons.sort((a, b) =>
+ a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1
+ );
+ }
+ );
protected render(): TemplateResult | void {
const repo = this.repo;
+ const addons = this._getAddons(this.addons, this.filter);
+
+ if (this.filter && addons.length < 1) {
+ return html`
+
+
+
+ No results found in "${repo.name}"
+
+
+
+ `;
+ }
return html`
@@ -34,31 +61,27 @@ class HassioAddonRepositoryEl extends LitElement {
- ${this.addons
- .sort((a, b) =>
- a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1
- )
- .map(
- (addon) => html`
-
-
-
-
-
- `
- )}
+ ${addons.map(
+ (addon) => html`
+
+
+
+
+
+ `
+ )}
`;
}
diff --git a/hassio/src/addon-store/hassio-addon-store.ts b/hassio/src/addon-store/hassio-addon-store.ts
index 35440bb58e..2035a5b16f 100644
--- a/hassio/src/addon-store/hassio-addon-store.ts
+++ b/hassio/src/addon-store/hassio-addon-store.ts
@@ -16,6 +16,7 @@ import {
reloadHassioAddons,
} from "../../../src/data/hassio";
import "../../../src/layouts/loading-screen";
+import "../components/hassio-search-input";
const sortRepos = (a: HassioAddonRepository, b: HassioAddonRepository) => {
if (a.slug === "local") {
@@ -37,10 +38,12 @@ class HassioAddonStore extends LitElement {
@property() public hass!: HomeAssistant;
@property() private _addons?: HassioAddonInfo[];
@property() private _repos?: HassioAddonRepository[];
+ @property() private _filter?: string;
public async refreshData() {
this._repos = undefined;
this._addons = undefined;
+ this._filter = undefined;
await reloadHassioAddons(this.hass);
await this._loadData();
}
@@ -67,6 +70,7 @@ class HassioAddonStore extends LitElement {
.hass=${this.hass}
.repo=${repo}
.addons=${addons}
+ .filter=${this._filter}
>
`);
}
@@ -77,6 +81,11 @@ class HassioAddonStore extends LitElement {
.repos=${this._repos}
>
+
+
${repos}
`;
}
@@ -104,6 +113,10 @@ class HassioAddonStore extends LitElement {
}
}
+ private async _filterChanged(e) {
+ this._filter = e.detail.value;
+ }
+
static get styles(): CSSResult {
return css`
hassio-addon-repository {
diff --git a/hassio/src/components/hassio-filter-addons.ts b/hassio/src/components/hassio-filter-addons.ts
new file mode 100644
index 0000000000..67bd0d4093
--- /dev/null
+++ b/hassio/src/components/hassio-filter-addons.ts
@@ -0,0 +1,13 @@
+import { HassioAddonInfo } from "../../../src/data/hassio";
+import * as Fuse from "fuse.js";
+
+export function filterAndSort(addons: HassioAddonInfo[], filter: string) {
+ const options: Fuse.FuseOptions = {
+ keys: ["name", "description", "slug"],
+ caseSensitive: false,
+ minMatchCharLength: 2,
+ threshold: 0.2,
+ };
+ const fuse = new Fuse(addons, options);
+ return fuse.search(filter);
+}
diff --git a/hassio/src/components/hassio-search-input.ts b/hassio/src/components/hassio-search-input.ts
new file mode 100644
index 0000000000..11a43eb4d1
--- /dev/null
+++ b/hassio/src/components/hassio-search-input.ts
@@ -0,0 +1,82 @@
+import { TemplateResult, html } from "lit-html";
+import {
+ css,
+ CSSResult,
+ customElement,
+ LitElement,
+ property,
+} from "lit-element";
+import { fireEvent } from "../../../src/common/dom/fire_event";
+import "@polymer/iron-icon/iron-icon";
+import "@polymer/paper-input/paper-input";
+import "@polymer/paper-icon-button/paper-icon-button";
+import "@material/mwc-button";
+
+@customElement("hassio-search-input")
+class HassioSearchInput extends LitElement {
+ @property() private filter?: string;
+
+ protected render(): TemplateResult | void {
+ return html`
+
+
+
+ ${this.filter &&
+ html`
+
+ `}
+
+
+ `;
+ }
+
+ private async _filterChanged(value: string) {
+ fireEvent(this, "value-changed", { value: String(value) });
+ }
+
+ private async _filterInputChanged(e) {
+ this._filterChanged(e.target.value);
+ }
+
+ private async _clearSearch() {
+ this._filterChanged("");
+ }
+
+ static get styles(): CSSResult {
+ return css`
+ paper-input {
+ flex: 1 1 auto;
+ margin: 0 16px;
+ }
+ .search-container {
+ display: inline-flex;
+ width: 100%;
+ align-items: center;
+ }
+ .prefix {
+ margin: 8px;
+ }
+ `;
+ }
+}
+
+declare global {
+ interface HTMLElementTagNameMap {
+ "hassio-search-input": HassioSearchInput;
+ }
+}
diff --git a/package.json b/package.json
index edaa0308dc..22c68baa9b 100644
--- a/package.json
+++ b/package.json
@@ -74,6 +74,7 @@
"deep-clone-simple": "^1.1.1",
"es6-object-assign": "^1.1.0",
"fecha": "^3.0.2",
+ "fuse.js": "^3.4.4",
"hls.js": "^0.12.4",
"home-assistant-js-websocket": "^4.1.2",
"intl-messageformat": "^2.2.0",
diff --git a/yarn.lock b/yarn.lock
index 42d45f0325..f35c71ba6c 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -6489,6 +6489,11 @@ functional-red-black-tree@^1.0.1:
resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
+fuse.js@^3.4.4:
+ version "3.4.4"
+ resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-3.4.4.tgz#f98f55fcb3b595cf6a3e629c5ffaf10982103e95"
+ integrity sha512-pyLQo/1oR5Ywf+a/tY8z4JygnIglmRxVUOiyFAbd11o9keUDpUJSMGRWJngcnkURj30kDHPmhoKY8ChJiz3EpQ==
+
g-status@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/g-status/-/g-status-2.0.2.tgz#270fd32119e8fc9496f066fe5fe88e0a6bc78b97"