Skip to content

Commit

Permalink
Adjust schedule helper UI with minute granularity (#21073)
Browse files Browse the repository at this point in the history
* Adjust schedule helper UI with minute granularity

* Update en.json

* ha-button
  • Loading branch information
karwosts authored Aug 28, 2024
1 parent 9c48dbf commit 395586d
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 18 deletions.
2 changes: 1 addition & 1 deletion src/components/ha-selector/ha-selector-time.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class HaTimeSelector extends LitElement {
clearable
.helper=${this.helper}
.label=${this.label}
enable-second
.enableSecond=${!this.selector.time?.no_second}
></ha-time-input>
`;
}
Expand Down
3 changes: 1 addition & 2 deletions src/data/selector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
133 changes: 133 additions & 0 deletions src/panels/config/helpers/forms/dialog-schedule-block-info.ts
Original file line number Diff line number Diff line change
@@ -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<string, string>;

@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`
<ha-dialog
open
@closed=${this.closeDialog}
.heading=${createCloseHeading(
this.hass,
this.hass!.localize(
"ui.dialogs.helper_settings.schedule.edit_schedule_block"
)
)}
>
<div>
<ha-form
.hass=${this.hass}
.schema=${SCHEMA}
.data=${this._data}
.error=${this._error}
.computeLabel=${this._computeLabelCallback}
@value-changed=${this._valueChanged}
></ha-form>
</div>
<ha-button
slot="secondaryAction"
class="warning"
@click=${this._deleteBlock}
>
${this.hass!.localize("ui.common.delete")}
</ha-button>
<ha-button slot="primaryAction" @click=${this._updateBlock}>
${this.hass!.localize("ui.common.save")}
</ha-button>
</ha-dialog>
`;
}

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<typeof SCHEMA>) => {
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);
41 changes: 27 additions & 14 deletions src/panels/config/helpers/forms/ha-schedule-form.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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;
Expand Down
26 changes: 26 additions & 0 deletions src/panels/config/helpers/forms/show-dialog-schedule-block-info.ts
Original file line number Diff line number Diff line change
@@ -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,
});
};
5 changes: 4 additions & 1 deletion src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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%]",
Expand Down

0 comments on commit 395586d

Please sign in to comment.