Add empty page to automation/script/scene config (#19075)

This commit is contained in:
Bram Kragten 2023-12-18 13:59:36 +01:00 committed by GitHub
parent 3e7fa66790
commit 45b7ebbe46
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 205 additions and 54 deletions

View File

@ -124,6 +124,12 @@ export class HaTabsSubpageDataTable extends LitElement {
*/ */
@property({ type: String }) public noDataText?: string; @property({ type: String }) public noDataText?: string;
/**
* Hides the data table and show an empty message.
* @type {Boolean}
*/
@property({ type: Boolean }) public empty = false;
@property() public route!: Route; @property() public route!: Route;
/** /**
@ -198,56 +204,61 @@ export class HaTabsSubpageDataTable extends LitElement {
.mainPage=${this.mainPage} .mainPage=${this.mainPage}
.supervisor=${this.supervisor} .supervisor=${this.supervisor}
> >
${!this.hideFilterMenu ${this.empty
? html` ? html`<div class="center">
<div slot="toolbar-icon"> <slot name="empty">${this.noDataText}</slot>
${this.narrow </div>`
: html`${!this.hideFilterMenu
? html`
<div slot="toolbar-icon">
${this.narrow
? html`
<div class="filter-menu">
${this.numHidden || this.activeFilters
? html`<span class="badge"
>${this.numHidden || "!"}</span
>`
: ""}
<slot name="filter-menu"></slot>
</div>
`
: ""}<slot name="toolbar-icon"></slot>
</div>
`
: ""}
${this.narrow
? html`
<div slot="header">
<slot name="header">
<div class="search-toolbar">${headerToolbar}</div>
</slot>
</div>
`
: ""}
<ha-data-table
.hass=${this.hass}
.columns=${this.columns}
.data=${this.data}
.noDataText=${this.noDataText}
.filter=${this.filter}
.selectable=${this.selectable}
.hasFab=${this.hasFab}
.id=${this.id}
.dir=${computeRTLDirection(this.hass)}
.clickable=${this.clickable}
.appendRow=${this.appendRow}
>
${!this.narrow
? html` ? html`
<div class="filter-menu"> <div slot="header">
${this.numHidden || this.activeFilters <slot name="header">
? html`<span class="badge" <div class="table-header">${headerToolbar}</div>
>${this.numHidden || "!"}</span </slot>
>`
: ""}
<slot name="filter-menu"></slot>
</div> </div>
` `
: ""}<slot name="toolbar-icon"></slot> : html` <div slot="header"></div> `}
</div> </ha-data-table>`}
`
: ""}
${this.narrow
? html`
<div slot="header">
<slot name="header">
<div class="search-toolbar">${headerToolbar}</div>
</slot>
</div>
`
: ""}
<ha-data-table
.hass=${this.hass}
.columns=${this.columns}
.data=${this.data}
.filter=${this.filter}
.selectable=${this.selectable}
.hasFab=${this.hasFab}
.id=${this.id}
.noDataText=${this.noDataText}
.dir=${computeRTLDirection(this.hass)}
.clickable=${this.clickable}
.appendRow=${this.appendRow}
>
${!this.narrow
? html`
<div slot="header">
<slot name="header">
<div class="table-header">${headerToolbar}</div>
</slot>
</div>
`
: html` <div slot="header"></div> `}
</ha-data-table>
<div slot="fab"><slot name="fab"></slot></div> <div slot="fab"><slot name="fab"></slot></div>
</hass-tabs-subpage> </hass-tabs-subpage>
`; `;
@ -374,6 +385,16 @@ export class HaTabsSubpageDataTable extends LitElement {
.filter-menu { .filter-menu {
position: relative; position: relative;
} }
.center {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
box-sizing: border-box;
height: 100%;
width: 100%;
padding: 16px;
}
`; `;
} }
} }

View File

@ -7,11 +7,19 @@ import {
mdiPlay, mdiPlay,
mdiPlayCircleOutline, mdiPlayCircleOutline,
mdiPlus, mdiPlus,
mdiRobotHappy,
mdiStopCircleOutline, mdiStopCircleOutline,
mdiTransitConnection, mdiTransitConnection,
} from "@mdi/js"; } from "@mdi/js";
import "@lrnwebcomponents/simple-tooltip/simple-tooltip"; import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
import { CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import {
css,
CSSResultGroup,
html,
LitElement,
nothing,
TemplateResult,
} from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one"; import memoizeOne from "memoize-one";
import { differenceInDays } from "date-fns/esm"; import { differenceInDays } from "date-fns/esm";
@ -295,6 +303,7 @@ class HaAutomationPicker extends LitElement {
.activeFilters=${this._activeFilters} .activeFilters=${this._activeFilters}
.columns=${this._columns(this.narrow, this.hass.locale)} .columns=${this._columns(this.narrow, this.hass.locale)}
.data=${this._automations(this.automations, this._filteredAutomations)} .data=${this._automations(this.automations, this._filteredAutomations)}
.empty=${!this.automations.length}
@row-click=${this._handleRowClicked} @row-click=${this._handleRowClicked}
.noDataText=${this.hass.localize( .noDataText=${this.hass.localize(
"ui.panel.config.automation.picker.no_automations" "ui.panel.config.automation.picker.no_automations"
@ -318,6 +327,35 @@ class HaAutomationPicker extends LitElement {
@related-changed=${this._relatedFilterChanged} @related-changed=${this._relatedFilterChanged}
> >
</ha-button-related-filter-menu> </ha-button-related-filter-menu>
${!this.automations.length
? html` <div class="empty" slot="empty">
<ha-svg-icon .path=${mdiRobotHappy}></ha-svg-icon>
<h1>
${this.hass.localize(
"ui.panel.config.automation.picker.empty_header"
)}
</h1>
<p>
${this.hass.localize(
"ui.panel.config.automation.picker.empty_text_1"
)}<br />
${this.hass.localize(
"ui.panel.config.automation.picker.empty_text_2"
)}
</p>
<a
href=${documentationUrl(this.hass, "/docs/automation/editor/")}
target="_blank"
rel="noreferrer"
>
<ha-button>
${this.hass.localize(
"ui.panel.config.automation.picker.learn_more"
)}
</ha-button>
</a>
</div>`
: nothing}
<ha-fab <ha-fab
slot="fab" slot="fab"
.label=${this.hass.localize( .label=${this.hass.localize(
@ -505,7 +543,15 @@ class HaAutomationPicker extends LitElement {
} }
static get styles(): CSSResultGroup { static get styles(): CSSResultGroup {
return haStyle; return [
haStyle,
css`
.empty {
--paper-font-headline_-_font-size: 28px;
--mdc-icon-size: 80px;
}
`,
];
} }
} }

View File

@ -3,12 +3,20 @@ import {
mdiDelete, mdiDelete,
mdiHelpCircle, mdiHelpCircle,
mdiInformationOutline, mdiInformationOutline,
mdiPalette,
mdiPencilOff, mdiPencilOff,
mdiPlay, mdiPlay,
mdiPlus, mdiPlus,
} from "@mdi/js"; } from "@mdi/js";
import "@lrnwebcomponents/simple-tooltip/simple-tooltip"; import "@lrnwebcomponents/simple-tooltip/simple-tooltip";
import { css, CSSResultGroup, html, LitElement, TemplateResult } from "lit"; import {
css,
CSSResultGroup,
html,
LitElement,
nothing,
TemplateResult,
} from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import memoizeOne from "memoize-one"; import memoizeOne from "memoize-one";
import { differenceInDays } from "date-fns/esm"; import { differenceInDays } from "date-fns/esm";
@ -21,6 +29,7 @@ import {
} from "../../../components/data-table/ha-data-table"; } from "../../../components/data-table/ha-data-table";
import "../../../components/ha-button-related-filter-menu"; import "../../../components/ha-button-related-filter-menu";
import "../../../components/ha-fab"; import "../../../components/ha-fab";
import "../../../components/ha-button";
import "../../../components/ha-icon-button"; import "../../../components/ha-icon-button";
import "../../../components/ha-state-icon"; import "../../../components/ha-state-icon";
import "../../../components/ha-svg-icon"; import "../../../components/ha-svg-icon";
@ -214,6 +223,7 @@ class HaSceneDashboard extends LitElement {
.columns=${this._columns(this.hass.locale, this.narrow)} .columns=${this._columns(this.hass.locale, this.narrow)}
id="entity_id" id="entity_id"
.data=${this._scenes(this.scenes, this._filteredScenes)} .data=${this._scenes(this.scenes, this._filteredScenes)}
.empty=${!this.scenes.length}
.activeFilters=${this._activeFilters} .activeFilters=${this._activeFilters}
.noDataText=${this.hass.localize( .noDataText=${this.hass.localize(
"ui.panel.config.scene.picker.no_scenes" "ui.panel.config.scene.picker.no_scenes"
@ -238,6 +248,30 @@ class HaSceneDashboard extends LitElement {
@related-changed=${this._relatedFilterChanged} @related-changed=${this._relatedFilterChanged}
> >
</ha-button-related-filter-menu> </ha-button-related-filter-menu>
${!this.scenes.length
? html` <div class="empty" slot="empty">
<ha-svg-icon .path=${mdiPalette}></ha-svg-icon>
<h1>
${this.hass.localize(
"ui.panel.config.scene.picker.empty_header"
)}
</h1>
<p>
${this.hass.localize("ui.panel.config.scene.picker.empty_text")}
</p>
<a
href=${documentationUrl(this.hass, "/docs/scene/editor/")}
target="_blank"
rel="noreferrer"
>
<ha-button>
${this.hass.localize(
"ui.panel.config.scene.picker.learn_more"
)}
</ha-button>
</a>
</div>`
: nothing}
<a href="/config/scene/edit/new" slot="fab"> <a href="/config/scene/edit/new" slot="fab">
<ha-fab <ha-fab
.label=${this.hass.localize( .label=${this.hass.localize(
@ -350,6 +384,10 @@ class HaSceneDashboard extends LitElement {
a { a {
text-decoration: none; text-decoration: none;
} }
.empty {
--paper-font-headline_-_font-size: 28px;
--mdc-icon-size: 80px;
}
`, `,
]; ];
} }

View File

@ -5,10 +5,18 @@ import {
mdiInformationOutline, mdiInformationOutline,
mdiPlay, mdiPlay,
mdiPlus, mdiPlus,
mdiScriptText,
mdiTransitConnection, mdiTransitConnection,
} from "@mdi/js"; } from "@mdi/js";
import { differenceInDays } from "date-fns/esm"; import { differenceInDays } from "date-fns/esm";
import { CSSResultGroup, LitElement, TemplateResult, css, html } from "lit"; import {
CSSResultGroup,
LitElement,
TemplateResult,
css,
html,
nothing,
} from "lit";
import { customElement, property, state } from "lit/decorators"; import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map"; import { styleMap } from "lit/directives/style-map";
import memoizeOne from "memoize-one"; import memoizeOne from "memoize-one";
@ -241,6 +249,7 @@ class HaScriptPicker extends LitElement {
.tabs=${configSections.automations} .tabs=${configSections.automations}
.columns=${this._columns(this.narrow, this.hass.locale)} .columns=${this._columns(this.narrow, this.hass.locale)}
.data=${this._scripts(this.scripts, this._filteredScripts)} .data=${this._scripts(this.scripts, this._filteredScripts)}
.empty=${!this.scripts.length}
.activeFilters=${this._activeFilters} .activeFilters=${this._activeFilters}
id="entity_id" id="entity_id"
.noDataText=${this.hass.localize( .noDataText=${this.hass.localize(
@ -266,6 +275,32 @@ class HaScriptPicker extends LitElement {
@related-changed=${this._relatedFilterChanged} @related-changed=${this._relatedFilterChanged}
> >
</ha-button-related-filter-menu> </ha-button-related-filter-menu>
${!this.scripts.length
? html` <div class="empty" slot="empty">
<ha-svg-icon .path=${mdiScriptText}></ha-svg-icon>
<h1>
${this.hass.localize(
"ui.panel.config.script.picker.empty_header"
)}
</h1>
<p>
${this.hass.localize(
"ui.panel.config.script.picker.empty_text"
)}
</p>
<a
href=${documentationUrl(this.hass, "/docs/script/editor/")}
target="_blank"
rel="noreferrer"
>
<ha-button>
${this.hass.localize(
"ui.panel.config.script.picker.learn_more"
)}
</ha-button>
</a>
</div>`
: nothing}
<ha-fab <ha-fab
slot="fab" slot="fab"
?is-wide=${this.isWide} ?is-wide=${this.isWide}
@ -471,6 +506,10 @@ class HaScriptPicker extends LitElement {
a { a {
text-decoration: none; text-decoration: none;
} }
.empty {
--paper-font-headline_-_font-size: 28px;
--mdc-icon-size: 80px;
}
`, `,
]; ];
} }

View File

@ -2360,7 +2360,10 @@
"trigger": "Trigger", "trigger": "Trigger",
"actions": "Actions", "actions": "Actions",
"state": "State" "state": "State"
} },
"empty_header": "Start automating",
"empty_text_1": "The automation editor is an easy way of creating and editing automations.",
"empty_text_2": "Even if you're new to home automation."
}, },
"dialog_new": { "dialog_new": {
"header": "Create automation", "header": "Create automation",
@ -3059,7 +3062,9 @@
"state": "State" "state": "State"
}, },
"delete": "[%key:ui::common::delete%]", "delete": "[%key:ui::common::delete%]",
"duplicate": "[%key:ui::common::duplicate%]" "duplicate": "[%key:ui::common::duplicate%]",
"empty_header": "Create your first script",
"empty_text": "Scripts allow you to perform a sequence of actions."
}, },
"dialog_new": { "dialog_new": {
"header": "Create script", "header": "Create script",
@ -3159,7 +3164,9 @@
"state": "State", "state": "State",
"name": "Name", "name": "Name",
"last_activated": "Last activated" "last_activated": "Last activated"
} },
"empty_header": "Create your first scene",
"empty_text": "Scenes are an easy way to store and replicate the state of devices."
}, },
"editor": { "editor": {
"default_name": "New scene", "default_name": "New scene",