Catch calender events fetch errors and keep UI working (#14517)

Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
Philip Allgaier 2022-12-06 18:28:16 +01:00 committed by GitHub
parent 0001cad423
commit 076a6c4459
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 87 additions and 14 deletions

View File

@ -56,13 +56,14 @@ export const fetchCalendarEvents = async (
start: Date,
end: Date,
calendars: Calendar[]
): Promise<CalendarEvent[]> => {
): Promise<{ events: CalendarEvent[]; errors: string[] }> => {
const params = encodeURI(
`?start=${start.toISOString()}&end=${end.toISOString()}`
);
const calEvents: CalendarEvent[] = [];
const promises: Promise<any>[] = [];
const errors: string[] = [];
const promises: Promise<CalendarEvent[]>[] = [];
calendars.forEach((cal) => {
promises.push(
@ -73,9 +74,15 @@ export const fetchCalendarEvents = async (
);
});
const results = await Promise.all(promises);
results.forEach((result, idx) => {
for (const [idx, promise] of promises.entries()) {
let result: CalendarEvent[];
try {
// eslint-disable-next-line no-await-in-loop
result = await promise;
} catch (err) {
errors.push(calendars[idx].entity_id);
continue;
}
const cal = calendars[idx];
result.forEach((ev) => {
const eventStart = getCalendarDate(ev.start);
@ -104,9 +111,9 @@ export const fetchCalendarEvents = async (
calEvents.push(event);
});
});
}
return calEvents;
return { events: calEvents, errors };
};
const getCalendarDate = (dateObj: any): string | undefined => {

View File

@ -97,6 +97,8 @@ export class HAFullCalendar extends LitElement {
@property() public initialView: FullCalendarView = "dayGridMonth";
@property({ attribute: false }) public error?: string = undefined;
private calendar?: Calendar;
private _viewButtons?: ToggleButton[];
@ -116,6 +118,14 @@ export class HAFullCalendar extends LitElement {
return html`
${this.calendar
? html`
${this.error
? html`<ha-alert
alert-type="error"
dismissable
@alert-dismissed-clicked=${this._clearError}
>${this.error}</ha-alert
>`
: ""}
<div class="header">
${!this.narrow
? html`
@ -380,6 +390,10 @@ export class HAFullCalendar extends LitElement {
);
});
private _clearError() {
this.error = undefined;
}
static get styles(): CSSResultGroup {
return [
haStyle,
@ -449,6 +463,11 @@ export class HAFullCalendar extends LitElement {
z-index: 1;
}
ha-alert {
display: block;
margin: 4px 0;
}
#calendar {
flex-grow: 1;
background-color: var(

View File

@ -15,6 +15,7 @@ import { customElement, property, state } from "lit/decorators";
import { styleMap } from "lit/directives/style-map";
import { LocalStorage } from "../../common/decorators/local-storage";
import { HASSDomEvent } from "../../common/dom/fire_event";
import { computeStateName } from "../../common/entity/compute_state_name";
import "../../components/ha-card";
import "../../components/ha-icon-button";
import "../../components/ha-menu-button";
@ -40,6 +41,8 @@ class PanelCalendar extends LitElement {
@state() private _events: CalendarEvent[] = [];
@state() private _error?: string = undefined;
@LocalStorage("deSelectedCalendars", true)
private _deSelectedCalendars: string[] = [];
@ -101,6 +104,7 @@ class PanelCalendar extends LitElement {
.calendars=${this._calendars}
.narrow=${this.narrow}
.hass=${this.hass}
.error=${this._error}
@view-changed=${this._handleViewChanged}
></ha-full-calendar>
</div>
@ -118,9 +122,9 @@ class PanelCalendar extends LitElement {
start: Date,
end: Date,
calendars: Calendar[]
): Promise<CalendarEvent[]> {
): Promise<{ events: CalendarEvent[]; errors: string[] }> {
if (!calendars.length) {
return [];
return { events: [], errors: [] };
}
return fetchCalendarEvents(this.hass, start, end, calendars);
@ -135,8 +139,9 @@ class PanelCalendar extends LitElement {
const checked = ev.target.checked;
if (checked) {
const events = await this._fetchEvents(this._start!, this._end!, [cal]);
this._events = [...this._events, ...events];
const result = await this._fetchEvents(this._start!, this._end!, [cal]);
this._events = [...this._events, ...result.events];
this._handleErrors(result.errors);
this._deSelectedCalendars = this._deSelectedCalendars.filter(
(deCal) => deCal !== cal.entity_id
);
@ -161,19 +166,40 @@ class PanelCalendar extends LitElement {
): Promise<void> {
this._start = ev.detail.start;
this._end = ev.detail.end;
this._events = await this._fetchEvents(
const result = await this._fetchEvents(
this._start,
this._end,
this._selectedCalendars
);
this._events = result.events;
this._handleErrors(result.errors);
}
private async _handleRefresh(): Promise<void> {
this._events = await this._fetchEvents(
const result = await this._fetchEvents(
this._start!,
this._end!,
this._selectedCalendars
);
this._events = result.events;
this._handleErrors(result.errors);
}
private _handleErrors(error_entity_ids: string[]) {
this._error = undefined;
if (error_entity_ids.length > 0) {
const nameList = error_entity_ids
.map((error_entity_id) =>
this.hass!.states[error_entity_id]
? computeStateName(this.hass!.states[error_entity_id])
: error_entity_id
)
.join(", ");
this._error = `${this.hass!.localize(
"ui.components.calendar.event_retrieval_error"
)} ${nameList}`;
}
}
static get styles(): CSSResultGroup {

View File

@ -10,6 +10,7 @@ import { customElement, property, state, query } from "lit/decorators";
import { getColorByIndex } from "../../../common/color/colors";
import { applyThemesOnElement } from "../../../common/dom/apply_themes_on_element";
import { HASSDomEvent } from "../../../common/dom/fire_event";
import { computeStateName } from "../../../common/entity/compute_state_name";
import { debounce } from "../../../common/util/debounce";
import "../../../components/ha-card";
import {
@ -69,6 +70,8 @@ export class HuiCalendarCard extends LitElement implements LovelaceCard {
@state() private _veryNarrow = false;
@state() private _error?: string = undefined;
@query("ha-full-calendar", true) private _calendar?: HAFullCalendar;
private _startDate?: Date;
@ -131,6 +134,7 @@ export class HuiCalendarCard extends LitElement implements LovelaceCard {
.hass=${this.hass}
.views=${views}
.initialView=${this._config.initial_view!}
.error=${this._error}
@view-changed=${this._handleViewChanged}
></ha-full-calendar>
</ha-card>
@ -169,12 +173,28 @@ export class HuiCalendarCard extends LitElement implements LovelaceCard {
return;
}
this._events = await fetchCalendarEvents(
this._error = undefined;
const result = await fetchCalendarEvents(
this.hass!,
this._startDate,
this._endDate,
this._calendars
);
this._events = result.events;
if (result.errors.length > 0) {
const nameList = result.errors
.map((error_entity_id) =>
this.hass!.states[error_entity_id]
? computeStateName(this.hass!.states[error_entity_id])
: error_entity_id
)
.join(", ");
this._error = `${this.hass!.localize(
"ui.components.calendar.event_retrieval_error"
)} ${nameList}`;
}
}
private _measureCard() {

View File

@ -634,6 +634,7 @@
"label": "Calendar",
"my_calendars": "My Calendars",
"today": "Today",
"event_retrieval_error": "Could not retrieve events for calendars: ",
"event": {
"add": "Add Event",
"delete": "Delete Event",