From 395586ddeb70bde0f70a98859715c92d032f3170 Mon Sep 17 00:00:00 2001 From: karwosts <32912880+karwosts@users.noreply.github.com> Date: Tue, 27 Aug 2024 23:41:53 -0700 Subject: [PATCH] Adjust schedule helper UI with minute granularity (#21073) * Adjust schedule helper UI with minute granularity * Update en.json * ha-button --- .../ha-selector/ha-selector-time.ts | 2 +- src/data/selector.ts | 3 +- .../forms/dialog-schedule-block-info.ts | 133 ++++++++++++++++++ .../config/helpers/forms/ha-schedule-form.ts | 41 ++++-- .../forms/show-dialog-schedule-block-info.ts | 26 ++++ src/translations/en.json | 5 +- 6 files changed, 192 insertions(+), 18 deletions(-) create mode 100644 src/panels/config/helpers/forms/dialog-schedule-block-info.ts create mode 100644 src/panels/config/helpers/forms/show-dialog-schedule-block-info.ts diff --git a/src/components/ha-selector/ha-selector-time.ts b/src/components/ha-selector/ha-selector-time.ts index bacba114fc..1f15896d15 100644 --- a/src/components/ha-selector/ha-selector-time.ts +++ b/src/components/ha-selector/ha-selector-time.ts @@ -30,7 +30,7 @@ export class HaTimeSelector extends LitElement { clearable .helper=${this.helper} .label=${this.label} - enable-second + .enableSecond=${!this.selector.time?.no_second} > `; } diff --git a/src/data/selector.ts b/src/data/selector.ts index 13aa16647e..6b17b4414b 100644 --- a/src/data/selector.ts +++ b/src/data/selector.ts @@ -427,8 +427,7 @@ export interface ThemeSelector { theme: { include_default?: boolean } | null; } export interface TimeSelector { - // eslint-disable-next-line @typescript-eslint/ban-types - time: {} | null; + time: { no_second?: boolean } | null; } export interface TriggerSelector { diff --git a/src/panels/config/helpers/forms/dialog-schedule-block-info.ts b/src/panels/config/helpers/forms/dialog-schedule-block-info.ts new file mode 100644 index 0000000000..1e1ddce467 --- /dev/null +++ b/src/panels/config/helpers/forms/dialog-schedule-block-info.ts @@ -0,0 +1,133 @@ +import { CSSResultGroup, html, LitElement, nothing } from "lit"; +import { property, state } from "lit/decorators"; +import { fireEvent } from "../../../../common/dom/fire_event"; +import { createCloseHeading } from "../../../../components/ha-dialog"; +import "../../../../components/ha-form/ha-form"; +import "../../../../components/ha-button"; +import { haStyleDialog } from "../../../../resources/styles"; +import { HomeAssistant } from "../../../../types"; +import { + ScheduleBlockInfo, + ScheduleBlockInfoDialogParams, +} from "./show-dialog-schedule-block-info"; +import type { SchemaUnion } from "../../../../components/ha-form/types"; + +const SCHEMA = [ + { + name: "from", + required: true, + selector: { time: { no_second: true } }, + }, + { + name: "to", + required: true, + selector: { time: { no_second: true } }, + }, +]; + +class DialogScheduleBlockInfo extends LitElement { + @property({ attribute: false }) public hass!: HomeAssistant; + + @state() private _error?: Record; + + @state() private _data?: ScheduleBlockInfo; + + @state() private _params?: ScheduleBlockInfoDialogParams; + + public showDialog(params: ScheduleBlockInfoDialogParams): void { + this._params = params; + this._error = undefined; + this._data = params.block; + } + + public closeDialog(): void { + this._params = undefined; + this._data = undefined; + fireEvent(this, "dialog-closed", { dialog: this.localName }); + } + + protected render() { + if (!this._params || !this._data) { + return nothing; + } + + return html` + +
+ +
+ + ${this.hass!.localize("ui.common.delete")} + + + ${this.hass!.localize("ui.common.save")} + +
+ `; + } + + private _valueChanged(ev: CustomEvent) { + this._error = undefined; + this._data = ev.detail.value; + } + + private _updateBlock() { + try { + this._params!.updateBlock!(this._data!); + this.closeDialog(); + } catch (err: any) { + this._error = { base: err ? err.message : "Unknown error" }; + } + } + + private _deleteBlock() { + try { + this._params!.deleteBlock!(); + this.closeDialog(); + } catch (err: any) { + this._error = { base: err ? err.message : "Unknown error" }; + } + } + + private _computeLabelCallback = (schema: SchemaUnion) => { + switch (schema.name) { + case "from": + return this.hass!.localize("ui.dialogs.helper_settings.schedule.start"); + case "to": + return this.hass!.localize("ui.dialogs.helper_settings.schedule.end"); + } + return ""; + }; + + static get styles(): CSSResultGroup { + return [haStyleDialog]; + } +} + +declare global { + interface HTMLElementTagNameMap { + "dialog-schedule-block-info": DialogScheduleBlockInfo; + } +} + +customElements.define("dialog-schedule-block-info", DialogScheduleBlockInfo); diff --git a/src/panels/config/helpers/forms/ha-schedule-form.ts b/src/panels/config/helpers/forms/ha-schedule-form.ts index 44614e8316..c6adbbc4ac 100644 --- a/src/panels/config/helpers/forms/ha-schedule-form.ts +++ b/src/panels/config/helpers/forms/ha-schedule-form.ts @@ -20,7 +20,7 @@ import "../../../../components/ha-icon-picker"; import "../../../../components/ha-textfield"; import { Schedule, ScheduleDay, weekdays } from "../../../../data/schedule"; import { TimeZone } from "../../../../data/translation"; -import { showConfirmationDialog } from "../../../../dialogs/generic/show-dialog-box"; +import { showScheduleBlockInfoDialog } from "./show-dialog-schedule-block-info"; import { haStyle } from "../../../../resources/styles"; import { HomeAssistant } from "../../../../types"; @@ -352,21 +352,34 @@ class HaScheduleForm extends LitElement { } private async _handleEventClick(info: any) { - if ( - !(await showConfirmationDialog(this, { - title: this.hass.localize("ui.dialogs.helper_settings.schedule.delete"), - text: this.hass.localize( - "ui.dialogs.helper_settings.schedule.confirm_delete" - ), - destructive: true, - confirmText: this.hass.localize("ui.common.delete"), - })) - ) { - return; - } const [day, index] = info.event.id.split("-"); - const value = [...this[`_${day}`]]; + const item = [...this[`_${day}`]][index]; + showScheduleBlockInfoDialog(this, { + block: item, + updateBlock: (newBlock) => this._updateBlock(day, index, newBlock), + deleteBlock: () => this._deleteBlock(day, index), + }); + } + private _updateBlock(day, index, newBlock) { + const [fromH, fromM, _fromS] = newBlock.from.split(":"); + newBlock.from = `${fromH}:${fromM}`; + const [toH, toM, _toS] = newBlock.to.split(":"); + newBlock.to = `${toH}:${toM}`; + if (Number(toH) === 0 && Number(toM) === 0) { + newBlock.to = "24:00"; + } + const newValue = { ...this._item }; + newValue[day] = [...this._item![day]]; + newValue[day][index] = newBlock; + + fireEvent(this, "value-changed", { + value: newValue, + }); + } + + private _deleteBlock(day, index) { + const value = [...this[`_${day}`]]; const newValue = { ...this._item }; value.splice(parseInt(index), 1); newValue[day] = value; diff --git a/src/panels/config/helpers/forms/show-dialog-schedule-block-info.ts b/src/panels/config/helpers/forms/show-dialog-schedule-block-info.ts new file mode 100644 index 0000000000..14a5909592 --- /dev/null +++ b/src/panels/config/helpers/forms/show-dialog-schedule-block-info.ts @@ -0,0 +1,26 @@ +import { fireEvent } from "../../../../common/dom/fire_event"; + +export interface ScheduleBlockInfo { + from: string; + to: string; +} + +export interface ScheduleBlockInfoDialogParams { + block: ScheduleBlockInfo; + updateBlock?: (update: ScheduleBlockInfo) => void; + deleteBlock?: () => void; +} + +export const loadScheduleBlockInfoDialog = () => + import("./dialog-schedule-block-info"); + +export const showScheduleBlockInfoDialog = ( + element: HTMLElement, + params: ScheduleBlockInfoDialogParams +): void => { + fireEvent(element, "show-dialog", { + dialogTag: "dialog-schedule-block-info", + dialogImport: loadScheduleBlockInfoDialog, + dialogParams: params, + }); +}; diff --git a/src/translations/en.json b/src/translations/en.json index 28342473a2..731f25bcb3 100644 --- a/src/translations/en.json +++ b/src/translations/en.json @@ -1538,7 +1538,10 @@ }, "schedule": { "delete": "Delete item?", - "confirm_delete": "Do you want to delete this item?" + "confirm_delete": "Do you want to delete this item?", + "edit_schedule_block": "Edit schedule block", + "start": "Start", + "end": "End" }, "template": { "time": "[%key:ui::panel::developer-tools::tabs::templates::time%]",