Skip to content

Commit

Permalink
Merge branch 'rc'
Browse files Browse the repository at this point in the history
  • Loading branch information
bramkragten committed Jan 3, 2025
2 parents c05054e + 47308e7 commit 7aa2136
Show file tree
Hide file tree
Showing 67 changed files with 867 additions and 285 deletions.
61 changes: 47 additions & 14 deletions build-scripts/gulp/compress.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import { constants } from "node:zlib";
import gulp from "gulp";
import brotli from "gulp-brotli";
import zopfli from "gulp-zopfli-green";
import paths from "../paths.cjs";

const filesGlob = "*.{js,json,css,svg,xml}";
Expand All @@ -12,17 +13,18 @@ const brotliOptions = {
[constants.BROTLI_PARAM_QUALITY]: constants.BROTLI_MAX_QUALITY,
},
};
const zopfliOptions = { threshold: 150 };

const compressModern = (rootDir, modernDir) =>
const compressModern = (rootDir, modernDir, compress) =>
gulp
.src([`${modernDir}/**/${filesGlob}`, `${rootDir}/sw-modern.js`], {
base: rootDir,
allowEmpty: true,
})
.pipe(brotli(brotliOptions))
.pipe(compress === "zopfli" ? zopfli(zopfliOptions) : brotli(brotliOptions))
.pipe(gulp.dest(rootDir));

const compressOther = (rootDir, modernDir) =>
const compressOther = (rootDir, modernDir, compress) =>
gulp
.src(
[
Expand All @@ -33,21 +35,52 @@ const compressOther = (rootDir, modernDir) =>
],
{ base: rootDir, allowEmpty: true }
)
.pipe(brotli(brotliOptions))
.pipe(compress === "zopfli" ? zopfli(zopfliOptions) : brotli(brotliOptions))
.pipe(gulp.dest(rootDir));

const compressAppModern = () =>
compressModern(paths.app_output_root, paths.app_output_latest);
const compressHassioModern = () =>
compressModern(paths.hassio_output_root, paths.hassio_output_latest);
const compressAppModernBrotli = () =>
compressModern(paths.app_output_root, paths.app_output_latest, "brotli");
const compressAppModernZopfli = () =>
compressModern(paths.app_output_root, paths.app_output_latest, "zopfli");

const compressAppOther = () =>
compressOther(paths.app_output_root, paths.app_output_latest);
const compressHassioOther = () =>
compressOther(paths.hassio_output_root, paths.hassio_output_latest);
const compressHassioModernBrotli = () =>
compressModern(
paths.hassio_output_root,
paths.hassio_output_latest,
"brotli"
);
const compressHassioModernZopfli = () =>
compressModern(
paths.hassio_output_root,
paths.hassio_output_latest,
"zopfli"
);

gulp.task("compress-app", gulp.parallel(compressAppModern, compressAppOther));
const compressAppOtherBrotli = () =>
compressOther(paths.app_output_root, paths.app_output_latest, "brotli");
const compressAppOtherZopfli = () =>
compressOther(paths.app_output_root, paths.app_output_latest, "zopfli");

const compressHassioOtherBrotli = () =>
compressOther(paths.hassio_output_root, paths.hassio_output_latest, "brotli");
const compressHassioOtherZopfli = () =>
compressOther(paths.hassio_output_root, paths.hassio_output_latest, "zopfli");

gulp.task(
"compress-app",
gulp.parallel(
compressAppModernBrotli,
compressAppOtherBrotli,
compressAppModernZopfli,
compressAppOtherZopfli
)
);
gulp.task(
"compress-hassio",
gulp.parallel(compressHassioModern, compressHassioOther)
gulp.parallel(
compressHassioModernBrotli,
compressHassioOtherBrotli,
compressHassioModernZopfli,
compressHassioOtherZopfli
)
);
10 changes: 5 additions & 5 deletions hassio/src/dialogs/backup/dialog-hassio-backup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -179,8 +179,8 @@ class HassioBackupDialog
}

private async _restoreClicked() {
this._restoringBackup = true;
const backupDetails = this._backupContent.backupDetails();
this._restoringBackup = true;

const supervisor = this._dialogParams?.supervisor;
if (supervisor !== undefined && supervisor.info.state !== "running") {
Expand All @@ -196,12 +196,12 @@ class HassioBackupDialog
if (
!(await showConfirmationDialog(this, {
title: this._localize(
this._backupContent.backupType === "full"
this._backup!.type === "full"
? "confirm_restore_full_backup_title"
: "confirm_restore_partial_backup_title"
),
text: this._localize(
this._backupContent.backupType === "full"
this._backup!.type === "full"
? "confirm_restore_full_backup_text"
: "confirm_restore_partial_backup_text"
),
Expand All @@ -216,9 +216,9 @@ class HassioBackupDialog
try {
await restoreBackup(
this.hass,
this._backupContent.backupType,
this._backup!.type,
this._backup!.slug,
backupDetails,
{ ...backupDetails, background: this._dialogParams?.onboarding },
!!this.hass && atLeastVersion(this.hass.config.version, 2021, 9)
);

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@
"element-internals-polyfill": "1.3.12",
"fuse.js": "7.0.0",
"google-timezones-json": "1.2.0",
"gulp-zopfli-green": "6.0.2",
"hls.js": "patch:hls.js@npm%3A1.5.7#~/.yarn/patches/hls.js-npm-1.5.7-f5bbd3d060.patch",
"home-assistant-js-websocket": "9.4.0",
"idb-keyval": "6.2.1",
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "home-assistant-frontend"
version = "20241224.0"
version = "20250103.0"
license = {text = "Apache-2.0"}
description = "The Home Assistant frontend"
readme = "README.md"
Expand Down
13 changes: 9 additions & 4 deletions src/common/array/ensure-array.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
type NonUndefined<T> = T extends undefined ? never : T;
type NonNullUndefined<T> = T extends undefined
? never
: T extends null
? never
: T;

/**
* Ensure that the input is an array or wrap it in an array
* @param value - The value to ensure is an array
*/
export function ensureArray(value: undefined): undefined;
export function ensureArray<T>(value: T | T[]): NonUndefined<T>[];
export function ensureArray<T>(value: T | readonly T[]): NonUndefined<T>[];
export function ensureArray(value: null): null;
export function ensureArray<T>(value: T | T[]): NonNullUndefined<T>[];
export function ensureArray<T>(value: T | readonly T[]): NonNullUndefined<T>[];
export function ensureArray(value) {
if (value === undefined || Array.isArray(value)) {
if (value === undefined || value === null || Array.isArray(value)) {
return value;
}
return [value];
Expand Down
13 changes: 10 additions & 3 deletions src/common/navigate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,16 @@ export interface NavigateOptions {
data?: any;
}

export const navigate = async (path: string, options?: NavigateOptions) => {
// max time to wait for dialogs to close before navigating
const DIALOG_WAIT_TIMEOUT = 500;

export const navigate = async (
path: string,
options?: NavigateOptions,
timestamp = Date.now()
) => {
const { history } = mainWindow;
if (history.state?.dialog) {
if (history.state?.dialog && Date.now() - timestamp < DIALOG_WAIT_TIMEOUT) {
const closed = await closeAllDialogs();
if (!closed) {
// eslint-disable-next-line no-console
Expand All @@ -26,7 +33,7 @@ export const navigate = async (path: string, options?: NavigateOptions) => {
return new Promise<boolean>((resolve) => {
// need to wait for history state to be updated in case a dialog was closed
setTimeout(() => {
navigate(path, options).then(resolve);
navigate(path, options, timestamp).then(resolve);
});
});
}
Expand Down
8 changes: 5 additions & 3 deletions src/common/util/copy-clipboard.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export const copyToClipboard = async (str) => {
export const copyToClipboard = async (str, rootEl?: HTMLElement) => {
if (navigator.clipboard) {
try {
await navigator.clipboard.writeText(str);
Expand All @@ -8,10 +8,12 @@ export const copyToClipboard = async (str) => {
}
}

const root = rootEl ?? document.body;

const el = document.createElement("textarea");
el.value = str;
document.body.appendChild(el);
root.appendChild(el);
el.select();
document.execCommand("copy");
document.body.removeChild(el);
root.removeChild(el);
};
20 changes: 19 additions & 1 deletion src/common/util/promise-timeout.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,25 @@
class TimeoutError extends Error {
public timeout: number;

constructor(timeout: number, ...params) {
super(...params);

// Maintains proper stack trace for where our error was thrown (only available on V8)
if (Error.captureStackTrace) {
Error.captureStackTrace(this, TimeoutError);
}

this.name = "TimeoutError";
// Custom debugging information
this.timeout = timeout;
this.message = `Timed out in ${timeout} ms.`;
}
}

export const promiseTimeout = (ms: number, promise: Promise<any> | any) => {
const timeout = new Promise((_resolve, reject) => {
setTimeout(() => {
reject(`Timed out in ${ms} ms.`);
reject(new TimeoutError(ms));
}, ms);
});

Expand Down
35 changes: 34 additions & 1 deletion src/components/chart/ha-chart-base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@ import { css, html, nothing, LitElement } from "lit";
import { customElement, property, state } from "lit/decorators";
import { classMap } from "lit/directives/class-map";
import { styleMap } from "lit/directives/style-map";
import { mdiRestart } from "@mdi/js";
import { fireEvent } from "../../common/dom/fire_event";
import { clamp } from "../../common/number/clamp";
import type { HomeAssistant } from "../../types";
import { debounce } from "../../common/util/debounce";
import { isMac } from "../../util/is_mac";
import "../ha-icon-button";

export const MIN_TIME_BETWEEN_UPDATES = 60 * 5 * 1000;

Expand Down Expand Up @@ -300,6 +302,16 @@ export class HaChartBase extends LitElement {
: this.hass.localize("ui.components.history_charts.zoom_hint")}
</div>
</div>
${this._isZoomed && this.chartType !== "timeline"
? html`<ha-icon-button
class="zoom-reset"
.path=${mdiRestart}
@click=${this._handleZoomReset}
title=${this.hass.localize(
"ui.components.history_charts.zoom_reset"
)}
></ha-icon-button>`
: nothing}
${this._tooltip
? html`<div
class="chart-tooltip ${classMap({
Expand Down Expand Up @@ -420,7 +432,11 @@ export class HaChartBase extends LitElement {
modifierKey,
speed: 0.05,
},
mode: "x",
mode:
this.chartType !== "timeline" &&
(this.options?.scales?.y as any)?.type === "category"
? "y"
: "x",
onZoomComplete: () => {
const isZoomed = this.chart?.isZoomedOrPanned() ?? false;
if (this._isZoomed && !isZoomed) {
Expand Down Expand Up @@ -541,6 +557,10 @@ export class HaChartBase extends LitElement {
}
}

private _handleZoomReset() {
this.chart?.resetZoom();
}

static get styles(): CSSResultGroup {
return css`
:host {
Expand All @@ -552,6 +572,9 @@ export class HaChartBase extends LitElement {
height: 0;
transition: height 300ms cubic-bezier(0.4, 0, 0.2, 1);
}
.chart-container {
position: relative;
}
canvas {
max-height: var(--chart-max-height, 400px);
}
Expand Down Expand Up @@ -670,6 +693,16 @@ export class HaChartBase extends LitElement {
background: rgba(0, 0, 0, 0.3);
box-shadow: 0 0 32px 32px rgba(0, 0, 0, 0.3);
}
.zoom-reset {
position: absolute;
top: 16px;
right: 4px;
background: var(--card-background-color);
border-radius: 4px;
--mdc-icon-button-size: 32px;
color: var(--primary-color);
border: 1px solid var(--divider-color);
}
`;
}
}
Expand Down
9 changes: 8 additions & 1 deletion src/components/data-table/ha-data-table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ export class HaDataTable extends LitElement {
return html`<div class="mdc-data-table__row">${row.content}</div>`;
}
if (row.empty) {
return html`<div class="mdc-data-table__row"></div>`;
return html`<div class="mdc-data-table__row empty-row"></div>`;
}
return html`
<div
Expand Down Expand Up @@ -960,6 +960,13 @@ export class HaDataTable extends LitElement {
width: var(--table-row-width, 100%);
}
.mdc-data-table__row.empty-row {
height: var(
--data-table-empty-row-height,
var(--data-table-row-height, 52px)
);
}
.mdc-data-table__row ~ .mdc-data-table__row {
border-top: 1px solid var(--divider-color);
}
Expand Down
4 changes: 3 additions & 1 deletion src/components/device/ha-device-picker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,9 @@ export class HaDevicePicker extends LitElement {

return {
id: device.id,
name: name,
name:
name ||
this.hass.localize("ui.components.device-picker.unnamed_device"),
area:
device.area_id && areas[device.area_id]
? areas[device.area_id].name
Expand Down
6 changes: 3 additions & 3 deletions src/components/ha-dialog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,10 +102,10 @@ export class HaDialog extends DialogBase {
align-items: var(--vertical-align-dialog, center);
}
.mdc-dialog__title {
padding: 12px 12px 0;
padding: 24px 24px 0 24px;
}
.mdc-dialog--scrollable .mdc-dialog__title {
padding: 12px;
.mdc-dialog__title:has(span) {
padding: 12px 12px 0;
}
.mdc-dialog__actions {
padding: 12px 24px 12px 24px;
Expand Down
1 change: 1 addition & 0 deletions src/components/ha-gauge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ export class HaGauge extends LitElement {
if (
!this._updated ||
(!changedProperties.has("value") &&
!changedProperties.has("valueText") &&
!changedProperties.has("label") &&
!changedProperties.has("_segment_label"))
) {
Expand Down
2 changes: 1 addition & 1 deletion src/components/ha-picture-upload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export class HaPictureUpload extends LitElement {
<ha-button
@click=${this._handleChangeClick}
.label=${this.hass.localize(
"ui.components.picture-upload.change_picture"
"ui.components.picture-upload.clear_picture"
)}
>
</ha-button>
Expand Down
Loading

0 comments on commit 7aa2136

Please sign in to comment.