Skip to content

Commit fc0a55b

Browse files
beth-panxnmetulev
andauthored
Fix bug to show more details in person card when rendered in context of mgt-agenda (#385)
* Update logic to support attendee queries in mgt-agenda * Update storybook for mgt-people * Refactor loadimage function. Add more details on get people by queries. * Refactor IDynamicPerson to separate file. Add logic to handle parallel procession of get people. * Update casing * Remove get image and add parallel processing. Co-authored-by: Nikola Metulev <[email protected]>
1 parent 2e27c5d commit fc0a55b

File tree

9 files changed

+187
-130
lines changed

9 files changed

+187
-130
lines changed

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

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -397,13 +397,9 @@ export class MgtAgenda extends MgtTemplatedComponent {
397397
return html`
398398
<mgt-people
399399
class="event-attendees"
400-
.people=${event.attendees.map(
401-
attendee =>
402-
({
403-
displayName: attendee.emailAddress.name,
404-
emailAddresses: [attendee.emailAddress]
405-
} as MicrosoftGraph.Contact)
406-
)}
400+
.peopleQueries=${event.attendees.map(attendee => {
401+
return attendee.emailAddress.address;
402+
})}
407403
></mgt-people>
408404
`;
409405
}

src/components/mgt-people-picker/mgt-people-picker.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,11 @@ import { classMap } from 'lit-html/directives/class-map';
1010
import { repeat } from 'lit-html/directives/repeat';
1111
import { findPerson, getPeopleFromGroup } from '../../graph/graph.people';
1212
import { getUser } from '../../graph/graph.user';
13+
import { IDynamicPerson } from '../../graph/types';
1314
import { Providers } from '../../Providers';
1415
import { ProviderState } from '../../providers/IProvider';
1516
import '../../styles/fabric-icon-font';
1617
import { debounce } from '../../utils/Utils';
17-
import { IDynamicPerson } from '../mgt-person/mgt-person';
1818
import { MgtFlyout } from '../sub-components/mgt-flyout/mgt-flyout';
1919
import { MgtTemplatedComponent } from '../templatedComponent';
2020
import { styles } from './mgt-people-picker-css';

src/components/mgt-people/mgt-people.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
99
import { customElement, html, property, TemplateResult } from 'lit-element';
1010
import { repeat } from 'lit-html/directives/repeat';
1111
import { getPeople, getPeopleFromGroup } from '../../graph/graph.people';
12-
import { getUsersForUserIds } from '../../graph/graph.user';
12+
import { getUsersForPeopleQueries, getUsersForUserIds } from '../../graph/graph.user';
13+
import { IDynamicPerson } from '../../graph/types';
1314
import { Providers } from '../../Providers';
1415
import { ProviderState } from '../../providers/IProvider';
1516
import '../../styles/fabric-icon-font';
1617
import { arraysAreEqual } from '../../utils/Utils';
17-
import { IDynamicPerson } from '../mgt-person/mgt-person';
1818
import { MgtTemplatedComponent } from '../templatedComponent';
1919
import { PersonCardInteraction } from './../PersonCardInteraction';
2020
import { styles } from './mgt-people-css';
@@ -90,6 +90,28 @@ export class MgtPeople extends MgtTemplatedComponent {
9090
})
9191
public people: IDynamicPerson[];
9292

93+
/**
94+
* allows developer to define queries of people for component
95+
* @type {string[]}
96+
*/
97+
98+
@property({
99+
attribute: 'people-queries',
100+
converter: (value, type) => {
101+
return value.split(',').map(v => v.trim());
102+
}
103+
})
104+
public get peopleQueries(): string[] {
105+
return this._peopleQueries;
106+
}
107+
public set peopleQueries(value: string[]) {
108+
if (arraysAreEqual(this._peopleQueries, value)) {
109+
return;
110+
}
111+
this._peopleQueries = value;
112+
this.requestStateUpdate(true);
113+
}
114+
93115
/**
94116
* developer determined max people shown in component
95117
* @type {number}
@@ -122,6 +144,7 @@ export class MgtPeople extends MgtTemplatedComponent {
122144

123145
private _groupId: string;
124146
private _userIds: string[];
147+
private _peopleQueries: string[];
125148

126149
constructor() {
127150
super();
@@ -270,6 +293,8 @@ export class MgtPeople extends MgtTemplatedComponent {
270293
this.people = await getPeopleFromGroup(graph, this.groupId);
271294
} else if (this.userIds) {
272295
this.people = await getUsersForUserIds(graph, this.userIds);
296+
} else if (this.peopleQueries) {
297+
this.people = await getUsersForPeopleQueries(graph, this.peopleQueries);
273298
} else {
274299
this.people = await getPeople(graph);
275300
}

src/components/mgt-person-card/mgt-person-card.ts

Lines changed: 15 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@
77

88
import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
99
import { customElement, html, property, TemplateResult } from 'lit-element';
10-
import { findPerson, findUserByEmail, getEmailFromGraphEntity } from '../../graph/graph.people';
11-
import { getContactPhoto, getUserPhoto, myPhoto } from '../../graph/graph.photos';
12-
import { getUser, getUserWithPhoto } from '../../graph/graph.user';
10+
import { findPerson, getEmailFromGraphEntity } from '../../graph/graph.people';
11+
import { getPersonImage } from '../../graph/graph.photos';
12+
import { getUserWithPhoto } from '../../graph/graph.user';
13+
import { IDynamicPerson } from '../../graph/types';
1314
import { Providers } from '../../Providers';
1415
import { ProviderState } from '../../providers/IProvider';
1516
import { getSvg, SvgIcon } from '../../utils/SvgHelper';
1617
import { TeamsHelper } from '../../utils/TeamsHelper';
17-
import { IDynamicPerson, MgtPerson } from '../mgt-person/mgt-person';
18+
import { MgtPerson } from '../mgt-person/mgt-person';
1819
import { MgtTemplatedComponent } from '../templatedComponent';
1920
import { styles } from './mgt-person-card-css';
2021

@@ -535,7 +536,11 @@ export class MgtPersonCard extends MgtTemplatedComponent {
535536
} else if (this.personImage === '@' && !this.personDetails.personImage) {
536537
// in some cases we might only have name or email, but need to find the image
537538
// use @ for the image value to search for an image
538-
this.loadImage();
539+
const image = await getPersonImage(graph, this.personDetails);
540+
if (image) {
541+
this.personDetails.personImage = image;
542+
this.personImage = image;
543+
}
539544
}
540545
} else if (this.userId || this.personQuery === 'me') {
541546
// Use userId or 'me' query to get the person and image
@@ -549,7 +554,11 @@ export class MgtPersonCard extends MgtTemplatedComponent {
549554

550555
if (people && people.length) {
551556
this.personDetails = people[0];
552-
this.loadImage();
557+
const image = await getPersonImage(graph, this.personDetails);
558+
if (image) {
559+
this.personDetails.personImage = image;
560+
this.personImage = image;
561+
}
553562
}
554563
}
555564
}
@@ -650,45 +659,6 @@ export class MgtPersonCard extends MgtTemplatedComponent {
650659
this.isExpanded = true;
651660
}
652661

653-
private async loadImage() {
654-
const provider = Providers.globalProvider;
655-
const graph = provider.graph.forComponent(this);
656-
const person = this.personDetails;
657-
let image: string;
658-
659-
if ((person as MicrosoftGraph.Person).userPrincipalName) {
660-
// try to find a user by userPrincipalName
661-
const userPrincipalName = (person as MicrosoftGraph.Person).userPrincipalName;
662-
image = await getUserPhoto(graph, userPrincipalName);
663-
} else {
664-
// try to find a user by e-mail
665-
const email = getEmailFromGraphEntity(person);
666-
if (email) {
667-
const users = await findUserByEmail(graph, email);
668-
if (users && users.length) {
669-
// Check for an OrganizationUser
670-
const orgUser = users.find(p => {
671-
return (p as any).personType && (p as any).personType.subclass === 'OrganizationUser';
672-
});
673-
if (orgUser) {
674-
// Lookup by userId
675-
const userId = (users[0] as MicrosoftGraph.Person).scoredEmailAddresses[0].address;
676-
image = await getUserPhoto(graph, userId);
677-
} else {
678-
// Lookup by contactId
679-
const contactId = users[0].id;
680-
image = await getContactPhoto(graph, contactId);
681-
}
682-
}
683-
}
684-
}
685-
686-
if (image) {
687-
this.personDetails.personImage = image;
688-
this.personImage = image;
689-
}
690-
}
691-
692662
private getImage(): string {
693663
if (this.personImage && this.personImage !== '@') {
694664
return this.personImage;

src/components/mgt-person/mgt-person.ts

Lines changed: 18 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
99
import { customElement, html, property, query, TemplateResult } from 'lit-element';
1010
import { classMap } from 'lit-html/directives/class-map';
11-
import { findPerson, findUserByEmail, getEmailFromGraphEntity } from '../../graph/graph.people';
12-
import { getContactPhoto, getUserPhoto, myPhoto } from '../../graph/graph.photos';
11+
import { findPerson, getEmailFromGraphEntity } from '../../graph/graph.people';
12+
import { getPersonImage } from '../../graph/graph.photos';
1313
import { getUserWithPhoto } from '../../graph/graph.user';
14+
import { IDynamicPerson } from '../../graph/types';
1415
import { Providers } from '../../Providers';
1516
import { ProviderState } from '../../providers/IProvider';
1617
import '../../styles/fabric-icon-font';
@@ -21,23 +22,6 @@ import { MgtTemplatedComponent } from '../templatedComponent';
2122
import { PersonCardInteraction } from './../PersonCardInteraction';
2223
import { styles } from './mgt-person-css';
2324

24-
/**
25-
* IDynamicPerson describes the person object we use throughout mgt-person,
26-
* which can be one of three similar Graph types.
27-
*
28-
* In addition, this custom type also defines the optional `personImage` property,
29-
* which is used to pass the image around to other components as part of the person object.
30-
*/
31-
export type IDynamicPerson = (MicrosoftGraph.User | MicrosoftGraph.Person | MicrosoftGraph.Contact) & {
32-
/**
33-
* personDetails.personImage is a toolkit injected property to pass image between components
34-
* an optimization to avoid fetching the image when unnecessary.
35-
*
36-
* @type {string}
37-
*/
38-
personImage?: string;
39-
};
40-
4125
/**
4226
* The person component is used to display a person or contact by using their photo, name, and/or email address.
4327
*
@@ -220,7 +204,7 @@ export class MgtPerson extends MgtTemplatedComponent {
220204
*/
221205
public render() {
222206
// Loading
223-
if (this.isLoadingState) {
207+
if (this.isLoadingState && !this.personDetails) {
224208
return this.renderLoading();
225209
}
226210

@@ -463,7 +447,6 @@ export class MgtPerson extends MgtTemplatedComponent {
463447
*/
464448
protected async loadState() {
465449
const provider = Providers.globalProvider;
466-
467450
if (!provider || provider.state === ProviderState.Loading) {
468451
return;
469452
}
@@ -473,74 +456,37 @@ export class MgtPerson extends MgtTemplatedComponent {
473456
return;
474457
}
475458

459+
const graph = provider.graph.forComponent(this);
476460
if (this.personDetails) {
477461
// in some cases we might only have name or email, but need to find the image
478462
// use @ for the image value to search for an image
479463
if (this.personImage === '@' && !this.personDetails.personImage) {
480-
this.loadImage();
464+
const image = await getPersonImage(graph, this.personDetails);
465+
if (image) {
466+
this.personDetails.personImage = image;
467+
this.personImage = image;
468+
}
481469
}
482-
return;
483-
}
484-
485-
// Use userId or 'me' query to get the person and image
486-
if (this.userId || this.personQuery === 'me') {
487-
const graph = provider.graph.forComponent(this);
470+
} else if (this.userId || this.personQuery === 'me') {
471+
// Use userId or 'me' query to get the person and image
488472
const person = await getUserWithPhoto(graph, this.userId);
489473

490474
this.personDetails = person;
491475
this.personImage = this.getImage();
492-
return;
493-
}
494-
495-
// Use the personQuery to find our person.
496-
if (this.personQuery) {
497-
const graph = provider.graph.forComponent(this);
476+
} else if (this.personQuery) {
477+
// Use the personQuery to find our person.
498478
const people = await findPerson(graph, this.personQuery);
499479

500480
if (people && people.length) {
501481
this.personDetails = people[0];
502-
this.loadImage();
503-
}
504-
}
505-
}
482+
const image = await getPersonImage(graph, people[0]);
506483

507-
private async loadImage() {
508-
const provider = Providers.globalProvider;
509-
const graph = provider.graph.forComponent(this);
510-
const person = this.personDetails;
511-
let image: string;
512-
513-
if ((person as MicrosoftGraph.Person).userPrincipalName) {
514-
// try to find a user by userPrincipalName
515-
const userPrincipalName = (person as MicrosoftGraph.Person).userPrincipalName;
516-
image = await getUserPhoto(graph, userPrincipalName);
517-
} else {
518-
// try to find a user by e-mail
519-
const email = getEmailFromGraphEntity(person);
520-
if (email) {
521-
const users = await findUserByEmail(graph, email);
522-
if (users && users.length) {
523-
// Check for an OrganizationUser
524-
const orgUser = users.find(p => {
525-
return (p as any).personType && (p as any).personType.subclass === 'OrganizationUser';
526-
});
527-
if (orgUser) {
528-
// Lookup by userId
529-
const userId = (users[0] as MicrosoftGraph.Person).scoredEmailAddresses[0].address;
530-
image = await getUserPhoto(graph, userId);
531-
} else {
532-
// Lookup by contactId
533-
const contactId = users[0].id;
534-
image = await getContactPhoto(graph, contactId);
535-
}
484+
if (image) {
485+
this.personDetails.personImage = image;
486+
this.personImage = image;
536487
}
537488
}
538489
}
539-
540-
if (image) {
541-
this.personDetails.personImage = image;
542-
this.personImage = image;
543-
}
544490
}
545491

546492
private getImage(): string {

src/graph/graph.photos.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@
66
*/
77

88
import { ResponseType } from '@microsoft/microsoft-graph-client';
9+
import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
910
import { IGraph } from '../IGraph';
1011
import { prepScopes } from '../utils/GraphHelpers';
1112
import { blobToBase64 } from '../utils/Utils';
13+
import { findUserByEmail, getEmailFromGraphEntity } from './graph.people';
14+
import { IDynamicPerson } from './types';
1215

1316
/**
1417
* retrieves a photo for the specified resource.
@@ -58,3 +61,41 @@ export function getUserPhoto(graph: IGraph, userId: string): Promise<string> {
5861
export function myPhoto(graph: IGraph): Promise<string> {
5962
return getPhotoForResource(graph, 'me', ['user.read']);
6063
}
64+
65+
/**
66+
* async promise, loads image of user
67+
*
68+
* @export
69+
*/
70+
export async function getPersonImage(graph: IGraph, person: IDynamicPerson) {
71+
let image: string;
72+
73+
if ((person as MicrosoftGraph.Person).userPrincipalName) {
74+
// try to find a user by userPrincipalName
75+
const userPrincipalName = (person as MicrosoftGraph.Person).userPrincipalName;
76+
image = await getUserPhoto(graph, userPrincipalName);
77+
} else {
78+
// try to find a user by e-mail
79+
const email = getEmailFromGraphEntity(person);
80+
if (email) {
81+
const users = await findUserByEmail(graph, email);
82+
if (users && users.length) {
83+
// Check for an OrganizationUser
84+
const orgUser = users.find(p => {
85+
return (p as any).personType && (p as any).personType.subclass === 'OrganizationUser';
86+
});
87+
if (orgUser) {
88+
// Lookup by userId
89+
const userId = (users[0] as MicrosoftGraph.Person).scoredEmailAddresses[0].address;
90+
image = await getUserPhoto(graph, userId);
91+
} else {
92+
// Lookup by contactId
93+
const contactId = users[0].id;
94+
image = await getContactPhoto(graph, contactId);
95+
}
96+
}
97+
}
98+
}
99+
100+
return image;
101+
}

0 commit comments

Comments
 (0)