From 34e59e543b9ac7ecbec19774121ef760f0adad2c Mon Sep 17 00:00:00 2001 From: Bram Kragten Date: Mon, 22 May 2023 10:39:06 +0200 Subject: [PATCH] Add support for offline db migration (#16566) --- src/data/recorder.ts | 14 ++++++++++ src/layouts/ha-init-page.ts | 17 +++++++++---- src/layouts/home-assistant.ts | 48 +++++++++++++++++++++++++++++++++-- src/state/connection-mixin.ts | 1 + src/state/hass-base-mixin.ts | 4 +++ 5 files changed, 77 insertions(+), 7 deletions(-) diff --git a/src/data/recorder.ts b/src/data/recorder.ts index ebcaa744ba..23752d16f2 100644 --- a/src/data/recorder.ts +++ b/src/data/recorder.ts @@ -2,6 +2,15 @@ import { computeStateName } from "../common/entity/compute_state_name"; import { HaDurationData } from "../components/ha-duration-input"; import { HomeAssistant } from "../types"; +export interface RecorderInfo { + backlog: number | null; + max_backlog: number; + migration_in_progress: boolean; + migration_is_live: boolean; + recording: boolean; + thread_running: boolean; +} + export type StatisticType = "change" | "state" | "sum" | "min" | "max" | "mean"; export interface Statistics { @@ -106,6 +115,11 @@ export interface StatisticsValidationResults { [statisticId: string]: StatisticsValidationResult[]; } +export const getRecorderInfo = (hass: HomeAssistant) => + hass.callWS({ + type: "recorder/info", + }); + export const getStatisticIds = ( hass: HomeAssistant, statistic_type?: "mean" | "sum" diff --git a/src/layouts/ha-init-page.ts b/src/layouts/ha-init-page.ts index 4d815bcfdd..d8e0b550ea 100644 --- a/src/layouts/ha-init-page.ts +++ b/src/layouts/ha-init-page.ts @@ -4,11 +4,13 @@ import { property, state } from "lit/decorators"; class HaInitPage extends LitElement { @property({ type: Boolean }) public error = false; + @property({ type: Boolean }) public migration = false; + @state() private _retryInSeconds = 60; - private _showProgressIndicatorTimeout?: NodeJS.Timeout; + private _showProgressIndicatorTimeout?: number; - private _retryInterval?: NodeJS.Timeout; + private _retryInterval?: number; protected render() { return this.error @@ -35,7 +37,11 @@ class HaInitPage extends LitElement {
-
Loading data
+
+ ${this.migration + ? "Database migration in progress, please wait this might take some time" + : "Loading data"} +
`; } @@ -56,11 +62,11 @@ class HaInitPage extends LitElement { } protected firstUpdated() { - this._showProgressIndicatorTimeout = setTimeout(() => { + this._showProgressIndicatorTimeout = window.setTimeout(() => { import("../components/ha-circular-progress"); }, 5000); - this._retryInterval = setInterval(() => { + this._retryInterval = window.setInterval(() => { const remainingSeconds = this._retryInSeconds--; if (remainingSeconds <= 0) { this._retry(); @@ -96,6 +102,7 @@ class HaInitPage extends LitElement { #loading-text { max-width: 350px; color: var(--primary-text-color); + text-align: center; } `; } diff --git a/src/layouts/home-assistant.ts b/src/layouts/home-assistant.ts index 0e72bbd868..5570f0a696 100644 --- a/src/layouts/home-assistant.ts +++ b/src/layouts/home-assistant.ts @@ -3,6 +3,7 @@ import { customElement, state } from "lit/decorators"; import { isNavigationClick } from "../common/dom/is-navigation-click"; import { navigate } from "../common/navigate"; import { getStorageDefaultPanelUrlPath } from "../data/panel"; +import { getRecorderInfo } from "../data/recorder"; import "../resources/custom-card-support"; import { HassElement } from "../state/hass-element"; import QuickBarMixin from "../state/quick-bar-mixin"; @@ -32,6 +33,8 @@ const panelUrl = (path: string) => { export class HomeAssistantAppEl extends QuickBarMixin(HassElement) { @state() private _route: Route; + @state() private _databaseMigration?: boolean; + private _panelUrl: string; private _haVersion?: string; @@ -65,8 +68,24 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) { `; } + willUpdate(changedProps: PropertyValues) { + if ( + this._databaseMigration === undefined && + changedProps.has("hass") && + this.hass?.config && + changedProps.get("hass")?.config !== this.hass?.config + ) { + this.checkDataBaseMigration(); + } + } + update(changedProps: PropertyValues) { - if (this.hass?.states && this.hass.config && this.hass.services) { + if ( + this.hass?.states && + this.hass.config && + this.hass.services && + this._databaseMigration === false + ) { this.render = this.renderHass; this.update = super.update; removeLaunchScreen(); @@ -131,6 +150,14 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) { changedProps.get("hass") as HomeAssistant | undefined ); } + if (changedProps.has("_databaseMigration")) { + if (this.render !== this.renderHass) { + this._renderInitInfo(false); + } else if (this._databaseMigration) { + // we already removed the launch screen, so we refresh to add it again to show the migration screen + location.reload(); + } + } } protected hassConnected() { @@ -174,6 +201,20 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) { } } + protected async checkDataBaseMigration() { + if (this.hass?.config?.components.includes("recorder")) { + const info = await getRecorderInfo(this.hass); + this._databaseMigration = + info.migration_in_progress && !info.migration_is_live; + if (this._databaseMigration) { + // check every 5 seconds if the migration is done + setTimeout(() => this.checkDataBaseMigration(), 5000); + } + } else { + this._databaseMigration = false; + } + } + protected async _initializeHass() { try { let result; @@ -250,7 +291,10 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) { private _renderInitInfo(error: boolean) { renderLaunchScreenInfoBox( - html`` + html`` ); } } diff --git a/src/state/connection-mixin.ts b/src/state/connection-mixin.ts index 7acfd4ce13..2e1a7927fe 100644 --- a/src/state/connection-mixin.ts +++ b/src/state/connection-mixin.ts @@ -249,6 +249,7 @@ export const connectionMixin = >( // @ts-ignore this.hass!.callWS({ type: "get_config" }).then((config: HassConfig) => { this._updateHass({ config }); + this.checkDataBaseMigration(); }); } diff --git a/src/state/hass-base-mixin.ts b/src/state/hass-base-mixin.ts index c0e7170328..7540aff285 100644 --- a/src/state/hass-base-mixin.ts +++ b/src/state/hass-base-mixin.ts @@ -38,6 +38,10 @@ export class HassBaseEl extends LitElement { // eslint-disable-next-line } + protected checkDataBaseMigration() { + // eslint-disable-next-line + } + protected hassChanged(hass, _oldHass) { this.__provideHass.forEach((el) => { (el as any).hass = hass;