mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Add Search to Hassio add-on store (#3108)
* ✨ Add search to hassio add-ons * 👕 Fix linter error * 👕 Lint fixes * 🔥 Remove search from dashboard for this PR * 🔥 Remove search from dasboard in this PR * 🔨 Suggested changes * 🔨 Change to fireEvent * 🔨 Convert definition * 🔥 Fix imports * 🔥 Revert styling test * 🔨 Fix search * 🔨 CSS fix * 🔨 Add smaller message to show no results found in repo * 🔨 Fixes * 🔨 CSS fixes * 🔨 Add types * 🎨 Max width * 🔨 Fix margin jump * 🔨 Add working memoizeOne * 👕 Fix linting / error on build
This commit is contained in:
parent
13761a20c5
commit
a89f0bd1cd
@ -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`
|
||||
<div class="card-group">
|
||||
<div class="title">
|
||||
<div class="description">
|
||||
No results found in "${repo.name}"
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
return html`
|
||||
<div class="card-group">
|
||||
<div class="title">
|
||||
@ -34,31 +61,27 @@ class HassioAddonRepositoryEl extends LitElement {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
${this.addons
|
||||
.sort((a, b) =>
|
||||
a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1
|
||||
)
|
||||
.map(
|
||||
(addon) => html`
|
||||
<paper-card
|
||||
.addon=${addon}
|
||||
class=${addon.available ? "" : "not_available"}
|
||||
@click=${this.addonTapped}
|
||||
>
|
||||
<div class="card-content">
|
||||
<hassio-card-content
|
||||
.hass=${this.hass}
|
||||
.title=${addon.name}
|
||||
.description=${addon.description}
|
||||
.available=${addon.available}
|
||||
.icon=${this.computeIcon(addon)}
|
||||
.iconTitle=${this.computeIconTitle(addon)}
|
||||
.iconClass=${this.computeIconClass(addon)}
|
||||
></hassio-card-content>
|
||||
</div>
|
||||
</paper-card>
|
||||
`
|
||||
)}
|
||||
${addons.map(
|
||||
(addon) => html`
|
||||
<paper-card
|
||||
.addon=${addon}
|
||||
class=${addon.available ? "" : "not_available"}
|
||||
@click=${this.addonTapped}
|
||||
>
|
||||
<div class="card-content">
|
||||
<hassio-card-content
|
||||
.hass=${this.hass}
|
||||
.title=${addon.name}
|
||||
.description=${addon.description}
|
||||
.available=${addon.available}
|
||||
.icon=${this.computeIcon(addon)}
|
||||
.iconTitle=${this.computeIconTitle(addon)}
|
||||
.iconClass=${this.computeIconClass(addon)}
|
||||
></hassio-card-content>
|
||||
</div>
|
||||
</paper-card>
|
||||
`
|
||||
)}
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
@ -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}
|
||||
></hassio-addon-repository>
|
||||
`);
|
||||
}
|
||||
@ -77,6 +81,11 @@ class HassioAddonStore extends LitElement {
|
||||
.repos=${this._repos}
|
||||
></hassio-repositories-editor>
|
||||
|
||||
<hassio-search-input
|
||||
.filter=${this._filter}
|
||||
@value-changed=${this._filterChanged}
|
||||
></hassio-search-input>
|
||||
|
||||
${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 {
|
||||
|
13
hassio/src/components/hassio-filter-addons.ts
Normal file
13
hassio/src/components/hassio-filter-addons.ts
Normal file
@ -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<HassioAddonInfo> = {
|
||||
keys: ["name", "description", "slug"],
|
||||
caseSensitive: false,
|
||||
minMatchCharLength: 2,
|
||||
threshold: 0.2,
|
||||
};
|
||||
const fuse = new Fuse(addons, options);
|
||||
return fuse.search(filter);
|
||||
}
|
82
hassio/src/components/hassio-search-input.ts
Normal file
82
hassio/src/components/hassio-search-input.ts
Normal file
@ -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`
|
||||
<div class="search-container">
|
||||
<paper-input
|
||||
label="Search"
|
||||
.value=${this.filter}
|
||||
@value-changed=${this._filterInputChanged}
|
||||
>
|
||||
<iron-icon
|
||||
icon="hassio:magnify"
|
||||
slot="prefix"
|
||||
class="prefix"
|
||||
></iron-icon>
|
||||
${this.filter &&
|
||||
html`
|
||||
<paper-icon-button
|
||||
slot="suffix"
|
||||
class="suffix"
|
||||
@click=${this._clearSearch}
|
||||
icon="hassio:close"
|
||||
alt="Clear"
|
||||
title="Clear"
|
||||
></paper-icon-button>
|
||||
`}
|
||||
</paper-input>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
@ -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",
|
||||
|
@ -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"
|
||||
|
Loading…
x
Reference in New Issue
Block a user