Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for offline db migration #16566

Merged
merged 2 commits into from
May 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/data/recorder.ts
Expand Up @@ -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 {
Expand Down Expand Up @@ -106,6 +115,11 @@ export interface StatisticsValidationResults {
[statisticId: string]: StatisticsValidationResult[];
}

export const getRecorderInfo = (hass: HomeAssistant) =>
hass.callWS<RecorderInfo>({
type: "recorder/info",
});

export const getStatisticIds = (
hass: HomeAssistant,
statistic_type?: "mean" | "sum"
Expand Down
17 changes: 12 additions & 5 deletions src/layouts/ha-init-page.ts
Expand Up @@ -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
Expand All @@ -35,7 +37,11 @@ class HaInitPage extends LitElement {
<div id="progress-indicator-wrapper">
<ha-circular-progress active></ha-circular-progress>
</div>
<div id="loading-text">Loading data</div>
<div id="loading-text">
${this.migration
? "Database migration in progress, please wait this might take some time"
: "Loading data"}
</div>
`;
}

Expand All @@ -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();
Expand Down Expand Up @@ -96,6 +102,7 @@ class HaInitPage extends LitElement {
#loading-text {
max-width: 350px;
color: var(--primary-text-color);
text-align: center;
}
`;
}
Expand Down
48 changes: 46 additions & 2 deletions src/layouts/home-assistant.ts
Expand Up @@ -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";
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -65,8 +68,24 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) {
`;
}

willUpdate(changedProps: PropertyValues<this>) {
if (
this._databaseMigration === undefined &&
changedProps.has("hass") &&
this.hass?.config &&
changedProps.get("hass")?.config !== this.hass?.config
) {
this.checkDataBaseMigration();
}
}

update(changedProps: PropertyValues<this>) {
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();
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -250,7 +291,10 @@ export class HomeAssistantAppEl extends QuickBarMixin(HassElement) {

private _renderInitInfo(error: boolean) {
renderLaunchScreenInfoBox(
html`<ha-init-page .error=${error}></ha-init-page>`
html`<ha-init-page
.error=${error}
.migration=${this._databaseMigration}
></ha-init-page>`
);
}
}
Expand Down
1 change: 1 addition & 0 deletions src/state/connection-mixin.ts
Expand Up @@ -249,6 +249,7 @@ export const connectionMixin = <T extends Constructor<HassBaseEl>>(
// @ts-ignore
this.hass!.callWS({ type: "get_config" }).then((config: HassConfig) => {
this._updateHass({ config });
this.checkDataBaseMigration();
});
}

Expand Down
4 changes: 4 additions & 0 deletions src/state/hass-base-mixin.ts
Expand Up @@ -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;
Expand Down