Skip to content

Commit

Permalink
Add summary card
Browse files Browse the repository at this point in the history
  • Loading branch information
piitaya committed Dec 9, 2024
1 parent de0c375 commit 5deaffa
Show file tree
Hide file tree
Showing 4 changed files with 311 additions and 90 deletions.
94 changes: 36 additions & 58 deletions src/data/backup_manager.ts
Original file line number Diff line number Diff line change
@@ -1,77 +1,59 @@
import type { HomeAssistant } from "../types";

export enum BackupManagerState {
IDLE = "idle",
CREATE_BACKUP = "create_backup",
RECEIVE_BACKUP = "receive_backup",
RESTORE_BACKUP = "restore_backup",
}
export type BackupManagerState =
| "idle"
| "create_backup"
| "receive_backup"
| "restore_backup";

export enum CreateBackupStage {
ADDON_REPOSITORIES = "addon_repositories",
ADDONS = "addons",
AWAIT_ADDON_RESTARTS = "await_addon_restarts",
DOCKER_CONFIG = "docker_config",
FINISHING_FILE = "finishing_file",
FOLDERS = "folders",
HOME_ASSISTANT = "home_assistant",
UPLOAD_TO_AGENTS = "upload_to_agents",
}
export type CreateBackupStage =
| "addon_repositories"
| "addons"
| "await_addon_restarts"
| "docker_config"
| "finishing_file"
| "folders"
| "home_assistant"
| "upload_to_agents";

export enum CreateBackupState {
COMPLETED = "completed",
FAILED = "failed",
IN_PROGRESS = "in_progress",
}
export type CreateBackupState = "completed" | "failed" | "in_progress";

export enum ReceiveBackupStage {
RECEIVE_FILE = "receive_file",
UPLOAD_TO_AGENTS = "upload_to_agents",
}
export type ReceiveBackupStage = "receive_file" | "upload_to_agents";

export enum ReceiveBackupState {
COMPLETED = "completed",
FAILED = "failed",
IN_PROGRESS = "in_progress",
}
export type ReceiveBackupState = "completed" | "failed" | "in_progress";

export enum RestoreBackupStage {
ADDON_REPOSITORIES = "addon_repositories",
ADDONS = "addons",
AWAIT_ADDON_RESTARTS = "await_addon_restarts",
AWAIT_HOME_ASSISTANT_RESTART = "await_home_assistant_restart",
CHECK_HOME_ASSISTANT = "check_home_assistant",
DOCKER_CONFIG = "docker_config",
DOWNLOAD_FROM_AGENT = "download_from_agent",
FOLDERS = "folders",
HOME_ASSISTANT = "home_assistant",
REMOVE_DELTA_ADDONS = "remove_delta_addons",
}
export type RestoreBackupStage =
| "addon_repositories"
| "addons"
| "await_addon_restarts"
| "await_home_assistant_restart"
| "check_home_assistant"
| "docker_config"
| "download_from_agent"
| "folders"
| "home_assistant"
| "remove_delta_addons";

export enum RestoreBackupState {
COMPLETED = "completed",
FAILED = "failed",
IN_PROGRESS = "in_progress",
}
export type RestoreBackupState = "completed" | "failed" | "in_progress";

type IdleEvent = {
manager_state: BackupManagerState.IDLE;
manager_state: "idle";
};

type CreateBackupEvent = {
manager_state: BackupManagerState.CREATE_BACKUP;
manager_state: "create_backup";
stage: CreateBackupStage | null;
state: CreateBackupState;
};

type ReceiveBackupEvent = {
manager_state: BackupManagerState.RECEIVE_BACKUP;
manager_state: "receive_backup";
stage: ReceiveBackupStage | null;
state: ReceiveBackupState;
};

type RestoreBackupEvent = {
manager_state: BackupManagerState.RESTORE_BACKUP;
manager_state: "restore_backup";
stage: RestoreBackupStage | null;
state: RestoreBackupState;
};
Expand All @@ -90,10 +72,6 @@ export const subscribeBackupEvents = (
type: "backup/subscribe_events",
});

export const isBackupInProgress = (state: ManagerStateEvent) =>
(state.manager_state === BackupManagerState.CREATE_BACKUP &&
state.state === CreateBackupState.IN_PROGRESS) ||
(state.manager_state === BackupManagerState.RECEIVE_BACKUP &&
state.state === ReceiveBackupState.IN_PROGRESS) ||
(state.manager_state === BackupManagerState.RESTORE_BACKUP &&
state.state === RestoreBackupState.IN_PROGRESS);
export const DEFAULT_MANAGER_STATE: ManagerStateEvent = {
manager_state: "idle",
};
108 changes: 108 additions & 0 deletions src/panels/config/backup/components/ha-backup-summary-progress.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import type { ManagerStateEvent } from "../../../../data/backup_manager";
import type { HomeAssistant } from "../../../../types";
import "./ha-backup-summary-card";

@customElement("ha-backup-summary-progress")
export class HaBackupSummaryProgress extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;

@property({ attribute: false }) public manager!: ManagerStateEvent;

@property({ type: Boolean, attribute: "has-action" })
public hasAction = false;

private get _heading() {
switch (this.manager.manager_state) {
case "create_backup":
return "Creating backup";
case "restore_backup":
return "Restoring backup";
case "receive_backup":
return "Receiving backup";
default:
return "";
}
}

private get _description() {
switch (this.manager.manager_state) {
case "create_backup":
switch (this.manager.stage) {
case "addon_repositories":
case "addons":
return "Backing up add-ons";
case "await_addon_restarts":
return "Waiting for add-ons to restart";
case "docker_config":
return "Backing up Docker configuration";
case "finishing_file":
return "Finishing backup file";
case "folders":
return "Backing up folders";
case "home_assistant":
return "Backing up Home Assistant";
case "upload_to_agents":
return "Uploading to locations";
default:
return "";
}
case "restore_backup":
switch (this.manager.stage) {
case "addon_repositories":
case "addons":
return "Restoring add-ons";
case "await_addon_restarts":
return "Waiting for add-ons to restart";
case "await_home_assistant_restart":
return "Waiting for Home Assistant to restart";
case "check_home_assistant":
return "Checking Home Assistant";
case "docker_config":
return "Restoring Docker configuration";
case "download_from_agent":
return "Downloading from location";
case "folders":
return "Restoring folders";
case "home_assistant":
return "Restoring Home Assistant";
case "remove_delta_addons":
return "Removing delta add-ons";
default:
return "";
}
case "receive_backup":
switch (this.manager.stage) {
case "receive_file":
return "Receiving file";
case "upload_to_agents":
return "Uploading to locations";
default:
return "";
}
default:
return "";
}
}

protected render() {
return html`
<ha-backup-summary-card
.hass=${this.hass}
.heading=${this._heading}
.description=${this._description}
status="loading"
.hasAction=${this.hasAction}
>
<slot name="action" slot="action"></slot>
</ha-backup-summary-card>
`;
}
}

declare global {
interface HTMLElementTagNameMap {
"ha-backup-summary-progress": HaBackupSummaryProgress;
}
}
84 changes: 84 additions & 0 deletions src/panels/config/backup/components/ha-backup-summary-status.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { html, LitElement } from "lit";
import { customElement, property } from "lit/decorators";
import memoizeOne from "memoize-one";
import { formatShortDateTime } from "../../../../common/datetime/format_date_time";
import type { BackupContent } from "../../../../data/backup";
import type { ManagerStateEvent } from "../../../../data/backup_manager";
import type { HomeAssistant } from "../../../../types";
import "./ha-backup-summary-card";

@customElement("ha-backup-summary-status")
export class HaBackupSummaryProgress extends LitElement {
@property({ attribute: false }) public hass!: HomeAssistant;

@property({ attribute: false }) public manager!: ManagerStateEvent;

@property({ attribute: false }) public backups!: BackupContent[];

@property({ type: Boolean, attribute: "has-action" })
public hasAction = false;

private _lastBackup = memoizeOne((backups: BackupContent[]) => {
const sortedBackups = backups
// eslint-disable-next-line arrow-body-style
.filter((backup) => {
// TODO : only show backups with default flag
return backup;
})
.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime());

return sortedBackups[0] as BackupContent | undefined;
});

protected render() {
const lastBackup = this._lastBackup(this.backups);

if (!lastBackup) {
return html`
<ha-backup-summary-card
heading="No backup available"
description="You have not created any backups yet."
.hasAction=${this.hasAction}
status="warning"
>
<slot name="action" slot="action"></slot>
</ha-backup-summary-card>
`;
}

const lastBackupDate = new Date(lastBackup.date);
const lastBackupPeriod = new Date().getTime() - lastBackupDate.getTime();
const numberOfDays = Math.floor(lastBackupPeriod / (1000 * 60 * 60 * 24));

// TODO : Improve time format
const description = `Last successful backup ${formatShortDateTime(lastBackupDate, this.hass.locale, this.hass.config)} and synced to ${lastBackup.agent_ids?.length} locations`;
if (numberOfDays > 8) {
return html`
<ha-backup-summary-card
heading=${`No backup for ${numberOfDays} days`}
description=${description}
.hasAction=${this.hasAction}
status="warning"
>
<slot name="action" slot="action"></slot>
</ha-backup-summary-card>
`;
}
return html`
<ha-backup-summary-card
heading=${`Backed up`}
description=${description}
.hasAction=${this.hasAction}
status="success"
>
<slot name="action" slot="action"></slot>
</ha-backup-summary-card>
`;
}
}

declare global {
interface HTMLElementTagNameMap {
"ha-backup-summary-status": HaBackupSummaryProgress;
}
}
Loading

0 comments on commit 5deaffa

Please sign in to comment.