Skip to content

Commit 6efb757

Browse files
authored
Fixed mgt-agenda days not working and added support for paging (#340)
* Fixed loadState getting called prematurely * added page iterator
1 parent f5c0975 commit 6efb757

File tree

4 files changed

+223
-55
lines changed

4 files changed

+223
-55
lines changed

src/components/baseComponent.ts

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ export abstract class MgtBaseComponent extends LitElement {
7878
}
7979

8080
/**
81-
* A flag to check if the component's firstUpdated method has fired.
81+
* A flag to check if the component is loading data state.
8282
*
8383
* @protected
8484
* @memberof MgtBaseComponent
@@ -87,6 +87,18 @@ export abstract class MgtBaseComponent extends LitElement {
8787
return this._isLoadingState;
8888
}
8989

90+
/**
91+
* A flag to check if the component has updated once.
92+
*
93+
* @readonly
94+
* @protected
95+
* @type {boolean}
96+
* @memberof MgtBaseComponent
97+
*/
98+
protected get isFirstUpdated(): boolean {
99+
return this._isFirstUpdated;
100+
}
101+
90102
private static _useShadowRoot: boolean = true;
91103

92104
/**
@@ -96,6 +108,7 @@ export abstract class MgtBaseComponent extends LitElement {
96108
@property({ attribute: false })
97109
private _isLoadingState: boolean = false;
98110

111+
private _isFirstUpdated = false;
99112
private _currentLoadStatePromise: Promise<unknown>;
100113

101114
constructor() {
@@ -126,6 +139,7 @@ export abstract class MgtBaseComponent extends LitElement {
126139
*/
127140
protected firstUpdated(changedProperties): void {
128141
super.firstUpdated(changedProperties);
142+
this._isFirstUpdated = true;
129143
Providers.onProviderUpdated(() => this.requestStateUpdate());
130144
this.requestStateUpdate();
131145
}
@@ -193,6 +207,11 @@ export abstract class MgtBaseComponent extends LitElement {
193207
* @memberof MgtBaseComponent
194208
*/
195209
protected async requestStateUpdate(force: boolean = false): Promise<unknown> {
210+
// the component is still bootstraping - wait until first updated
211+
if (!this._isFirstUpdated) {
212+
return;
213+
}
214+
196215
// Wait for the current load promise to complete (unless forced).
197216
if (this._isLoadingState && !force) {
198217
await this._currentLoadStatePromise;
@@ -218,6 +237,8 @@ export abstract class MgtBaseComponent extends LitElement {
218237
// Return the load state promise.
219238
// If loading + forced, chain the promises.
220239
return (this._currentLoadStatePromise =
221-
this._isLoadingState && force ? this._currentLoadStatePromise.then(() => loadStatePromise) : loadStatePromise);
240+
this._isLoadingState && !!this._currentLoadStatePromise && force
241+
? this._currentLoadStatePromise.then(() => loadStatePromise)
242+
: loadStatePromise);
222243
}
223244
}

src/components/mgt-agenda/mgt-agenda.graph.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,23 @@
88
import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
99
import { IGraph } from '../../IGraph';
1010
import { prepScopes } from '../../utils/GraphHelpers';
11+
import { GraphPageIterator } from '../../utils/GraphPageIterator';
1112

1213
/**
13-
* async promise, returns Calender events associated with either the logged in user or a specific groupId
14+
* returns Calender events iterator associated with either the logged in user or a specific groupId
1415
*
1516
* @param {Date} startDateTime
1617
* @param {Date} endDateTime
1718
* @param {string} [groupId]
1819
* @returns {(Promise<Event[]>)}
1920
* @memberof Graph
2021
*/
21-
export async function getEvents(
22+
export function getEventsPageIterator(
2223
graph: IGraph,
2324
startDateTime: Date,
2425
endDateTime: Date,
2526
groupId?: string
26-
): Promise<MicrosoftGraph.Event[]> {
27+
): Promise<GraphPageIterator<MicrosoftGraph.Event>> {
2728
const scopes = 'calendars.read';
2829

2930
const sdt = `startdatetime=${startDateTime.toISOString()}`;
@@ -39,10 +40,10 @@ export async function getEvents(
3940

4041
uri += `/calendarview?${sdt}&${edt}`;
4142

42-
const calendarView = await graph
43+
const request = graph
4344
.api(uri)
4445
.middlewareOptions(prepScopes(scopes))
45-
.orderby('start/dateTime')
46-
.get();
47-
return calendarView ? calendarView.value : null;
46+
.orderby('start/dateTime');
47+
48+
return GraphPageIterator.create<MicrosoftGraph.Event>(graph, request);
4849
}

src/components/mgt-agenda/mgt-agenda.ts

Lines changed: 99 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ import { getDayOfWeekString, getMonthString } from '../../utils/Utils';
1515
import '../mgt-person/mgt-person';
1616
import { MgtTemplatedComponent } from '../templatedComponent';
1717
import { styles } from './mgt-agenda-css';
18-
import { getEvents } from './mgt-agenda.graph';
18+
import { getEventsPageIterator } from './mgt-agenda.graph';
1919

2020
/**
2121
* Web Component which represents events in a user or group calendar.
@@ -50,46 +50,64 @@ export class MgtAgenda extends MgtTemplatedComponent {
5050
}
5151

5252
/**
53-
* array containing events from user agenda.
54-
* @type {Array<MicrosoftGraph.Event>}
53+
* stores current date for initial calender selection in events.
54+
* @type {string}
5555
*/
5656
@property({
57-
attribute: 'events'
57+
attribute: 'date',
58+
type: String
5859
})
59-
public events: MicrosoftGraph.Event[];
60+
public get date(): string {
61+
return this._date;
62+
}
63+
public set date(value) {
64+
if (this._date === value) {
65+
return;
66+
}
6067

61-
/**
62-
* allows developer to define agenda to group events by day.
63-
* @type {Boolean}
64-
*/
65-
@property({
66-
attribute: 'group-by-day',
67-
reflect: true,
68-
type: Boolean
69-
})
70-
public groupByDay: boolean;
68+
this._date = value;
69+
this.requestStateUpdate(true);
70+
}
7171

7272
/**
73-
* stores current date for initial calender selection in events.
73+
* determines if agenda events come from specific group
7474
* @type {string}
7575
*/
7676
@property({
77-
attribute: 'date',
78-
reflect: true,
77+
attribute: 'group-id',
7978
type: String
8079
})
81-
public date: string;
80+
public get groupId(): string {
81+
return this._groupId;
82+
}
83+
public set groupId(value) {
84+
if (this._groupId === value) {
85+
return;
86+
}
87+
88+
this._groupId = value;
89+
this.requestStateUpdate(true);
90+
}
8291

8392
/**
8493
* sets number of days until end date, 3 is the default
8594
* @type {number}
8695
*/
8796
@property({
8897
attribute: 'days',
89-
reflect: true,
9098
type: Number
9199
})
92-
public days: number;
100+
public get days(): number {
101+
return this._days;
102+
}
103+
public set days(value) {
104+
if (this._days === value) {
105+
return;
106+
}
107+
108+
this._days = value;
109+
this.requestStateUpdate(true);
110+
}
93111

94112
/**
95113
* allows developer to specify a different graph query that retrieves events
@@ -99,7 +117,26 @@ export class MgtAgenda extends MgtTemplatedComponent {
99117
attribute: 'event-query',
100118
type: String
101119
})
102-
public eventQuery: string;
120+
public get eventQuery(): string {
121+
return this._eventQuery;
122+
}
123+
public set eventQuery(value) {
124+
if (this._eventQuery === value) {
125+
return;
126+
}
127+
128+
this._eventQuery = value;
129+
this.requestStateUpdate(true);
130+
}
131+
132+
/**
133+
* array containing events from user agenda.
134+
* @type {Array<MicrosoftGraph.Event>}
135+
*/
136+
@property({
137+
attribute: 'events'
138+
})
139+
public events: MicrosoftGraph.Event[];
103140

104141
/**
105142
* allows developer to define max number of events shown
@@ -112,24 +149,29 @@ export class MgtAgenda extends MgtTemplatedComponent {
112149
public showMax: number;
113150

114151
/**
115-
* determines if agenda events come from specific group
116-
* @type {string}
152+
* allows developer to define agenda to group events by day.
153+
* @type {Boolean}
117154
*/
118155
@property({
119-
attribute: 'group-id',
120-
type: String
156+
attribute: 'group-by-day',
157+
type: Boolean
121158
})
122-
public groupId: string;
159+
public groupByDay: boolean;
123160

124161
/**
125162
* determines width available for agenda component.
126163
* @type {boolean}
127164
*/
128165
@property({ attribute: false }) private _isNarrow: boolean;
166+
@property({ attribute: false }) private _isLoadingEvents: boolean;
167+
168+
private _eventQuery: string;
169+
private _days: number = 3;
170+
private _groupId: string;
171+
private _date: string;
129172

130173
constructor() {
131174
super();
132-
this.days = 3;
133175
this.onResize = this.onResize.bind(this);
134176
}
135177

@@ -154,22 +196,6 @@ export class MgtAgenda extends MgtTemplatedComponent {
154196
super.disconnectedCallback();
155197
}
156198

157-
/**
158-
* Synchronizes property values when attributes change.
159-
*
160-
* @param {*} name
161-
* @param {*} oldValue
162-
* @param {*} newValue
163-
* @memberof MgtAgenda
164-
*/
165-
public attributeChangedCallback(name, oldValue, newValue) {
166-
if (oldValue !== newValue && (name === 'date' || name === 'days' || name === 'group-id')) {
167-
this.events = null;
168-
this.requestStateUpdate();
169-
}
170-
super.attributeChangedCallback(name, oldValue, newValue);
171-
}
172-
173199
/**
174200
* Invoked on each update to perform rendering tasks. This method must return a lit-html TemplateResult.
175201
* Setting properties inside this method will not trigger the element to update
@@ -179,7 +205,7 @@ export class MgtAgenda extends MgtTemplatedComponent {
179205
*/
180206
public render(): TemplateResult {
181207
// Loading
182-
if (this.isLoadingState) {
208+
if (this.isLoadingState && !this._isLoadingEvents) {
183209
return this.renderLoading();
184210
}
185211

@@ -204,10 +230,25 @@ export class MgtAgenda extends MgtTemplatedComponent {
204230
return html`
205231
<div class="agenda${this._isNarrow ? ' narrow' : ''}${this.groupByDay ? ' grouped' : ''}">
206232
${this.groupByDay ? this.renderGroups(events) : this.renderEvents(events)}
233+
${this._isLoadingEvents ? this.renderLoading() : html``}
207234
</div>
208235
`;
209236
}
210237

238+
/**
239+
* Request to reload the state.
240+
* Use reload instead of load to ensure loading events are fired.
241+
*
242+
* @protected
243+
* @memberof MgtBaseComponent
244+
*/
245+
protected async requestStateUpdate(force?: boolean) {
246+
if (force) {
247+
this.events = null;
248+
}
249+
super.requestStateUpdate(force);
250+
}
251+
211252
/**
212253
* Render the loading state
213254
*
@@ -484,9 +525,21 @@ export class MgtAgenda extends MgtTemplatedComponent {
484525
const end = new Date(start.getTime());
485526
end.setDate(start.getDate() + this.days);
486527
try {
487-
this.events = await getEvents(graph, start, end, this.groupId);
528+
const iterator = await getEventsPageIterator(graph, start, end, this.groupId);
529+
530+
if (iterator && iterator.value) {
531+
this._isLoadingEvents = true;
532+
this.events = iterator.value;
533+
534+
while (iterator.hasNext) {
535+
await iterator.next();
536+
this.events = iterator.value;
537+
}
538+
}
488539
} catch (error) {
489540
// noop - possible error with graph
541+
} finally {
542+
this._isLoadingEvents = false;
490543
}
491544
}
492545
}

0 commit comments

Comments
 (0)