Integrations - Add Search (#3361)

*  Add search to flow picker

* 🔨 Autofocus

* 🔨 squash extra space

* Update src/dialogs/config-flow/step-flow-pick-handler.ts

Co-Authored-By: Paulus Schoutsen <paulus@home-assistant.io>

* Update src/dialogs/config-flow/step-flow-pick-handler.ts

Co-Authored-By: Paulus Schoutsen <paulus@home-assistant.io>
This commit is contained in:
Timmo 2019-07-14 21:47:33 +01:00 committed by Paulus Schoutsen
parent 8bbc442b7e
commit cdb2a1a424
2 changed files with 138 additions and 10 deletions

View File

@ -0,0 +1,83 @@
import { TemplateResult, html } from "lit-html";
import {
css,
CSSResult,
customElement,
LitElement,
property,
} from "lit-element";
import { fireEvent } from "../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("search-input")
class SearchInput extends LitElement {
@property() private filter?: string;
protected render(): TemplateResult | void {
return html`
<div class="search-container">
<paper-input
autofocus
label="Search"
.value=${this.filter}
@value-changed=${this._filterInputChanged}
>
<iron-icon
icon="mdi:magnify"
slot="prefix"
class="prefix"
></iron-icon>
${this.filter &&
html`
<paper-icon-button
slot="suffix"
class="suffix"
@click=${this._clearSearch}
icon="mdi: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 {
"search-input": SearchInput;
}
}

View File

@ -1,10 +1,11 @@
import { import {
LitElement,
TemplateResult,
html,
css, css,
customElement,
CSSResult, CSSResult,
customElement,
html,
LitElement,
property,
TemplateResult,
} from "lit-element"; } from "lit-element";
import "@polymer/paper-spinner/paper-spinner-lite"; import "@polymer/paper-spinner/paper-spinner-lite";
import "@polymer/paper-item/paper-item"; import "@polymer/paper-item/paper-item";
@ -12,23 +13,62 @@ import "@polymer/paper-item/paper-item-body";
import { HomeAssistant } from "../../types"; import { HomeAssistant } from "../../types";
import { createConfigFlow } from "../../data/config_entries"; import { createConfigFlow } from "../../data/config_entries";
import { fireEvent } from "../../common/dom/fire_event"; import { fireEvent } from "../../common/dom/fire_event";
import memoizeOne from "memoize-one";
import * as Fuse from "fuse.js";
import "../../components/ha-icon-next"; import "../../components/ha-icon-next";
import "../../common/search/search-input";
interface HandlerObj {
name: string;
slug: string;
}
@customElement("step-flow-pick-handler") @customElement("step-flow-pick-handler")
class StepFlowPickHandler extends LitElement { class StepFlowPickHandler extends LitElement {
public hass!: HomeAssistant; @property() public hass!: HomeAssistant;
public handlers!: string[]; @property() public handlers!: string[];
@property() private filter?: string;
private _getHandlers = memoizeOne((h: string[], filter?: string) => {
const handlers: HandlerObj[] = h.map((handler) => {
return {
name: this.hass.localize(`component.${handler}.config.title`),
slug: handler,
};
});
if (filter) {
const options: Fuse.FuseOptions<HandlerObj> = {
keys: ["name", "slug"],
caseSensitive: false,
minMatchCharLength: 2,
threshold: 0.2,
};
const fuse = new Fuse(handlers, options);
return fuse.search(filter);
}
return handlers.sort((a, b) =>
a.name.toUpperCase() < b.name.toUpperCase() ? -1 : 1
);
});
protected render(): TemplateResult | void { protected render(): TemplateResult | void {
const handlers = this._getHandlers(this.handlers, this.filter);
return html` return html`
<h2>${this.hass.localize("ui.panel.config.integrations.new")}</h2> <h2>${this.hass.localize("ui.panel.config.integrations.new")}</h2>
<div> <div>
${this.handlers.map( <search-input
(handler) => .filter=${this.filter}
@value-changed=${this._filterChanged}
></search-input>
${handlers.map(
(handler: HandlerObj) =>
html` html`
<paper-item @click=${this._handlerPicked} .handler=${handler}> <paper-item @click=${this._handlerPicked} .handler=${handler}>
<paper-item-body> <paper-item-body>
${this.hass.localize(`component.${handler}.config.title`)} ${handler.name}
</paper-item-body> </paper-item-body>
<ha-icon-next></ha-icon-next> <ha-icon-next></ha-icon-next>
</paper-item> </paper-item>
@ -38,15 +78,20 @@ class StepFlowPickHandler extends LitElement {
`; `;
} }
private async _filterChanged(e) {
this.filter = e.detail.value;
}
private async _handlerPicked(ev) { private async _handlerPicked(ev) {
fireEvent(this, "flow-update", { fireEvent(this, "flow-update", {
stepPromise: createConfigFlow(this.hass, ev.currentTarget.handler), stepPromise: createConfigFlow(this.hass, ev.currentTarget.handler.slug),
}); });
} }
static get styles(): CSSResult { static get styles(): CSSResult {
return css` return css`
h2 { h2 {
margin-bottom: 2px;
padding-left: 16px; padding-left: 16px;
} }
div { div {