mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-24 09:46:36 +00:00
Catch calender events fetch errors and keep UI working (#14517)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
0001cad423
commit
076a6c4459
@ -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 => {
|
||||
|
@ -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(
|
||||
|
@ -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 {
|
||||
|
@ -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() {
|
||||
|
@ -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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user