microsoft-graph-toolkit icon indicating copy to clipboard operation
microsoft-graph-toolkit copied to clipboard

[BUG] Header missing from people search

Open FredrikEkstroem opened this issue 1 year ago • 9 comments

Describe the bug The people picker does not send the header "X-PeopleQuery-QuerySources: Mailbox,Directory” in the query https://graph.microsoft.com/v1.0/me/people?$search=%22Some%20Name%22&$top=6&$filter=personType/class%20eq%20%27Person%27. This means not all results are returned, only people "which are your saved contacts or people you are most likely to interact with", see documentation here . In our scenario this means we have many cases where the people picker returns 0 results, even though the user exist.

To Reproduce Steps to reproduce the behavior: Add a people picker

<PeoplePicker
  className={styles.pickerControl}
  selectionMode="single"
  ref={user}
/>

Search for someone and check the network traffic

Expected behavior Header should be added to include all people in search

Environment (please complete the following information):

  • OS: Windows
  • Browser: edge, chrome
  • Framework: React, MGT-SPFX
  • Context: Sharedpoint
  • Version @microsoft/[email protected]
  • Provider Msal2Provider/SimpleProvider

Additional context Releated bugs: #1224 #1723 I suspect it might also be the explanation for this #1387

Probably could be fixed if header was added to graph.people.ts something like

graphResult = await graph
      .api('/me/people')
      .search('"' + query + '"')
      .top(top)
      .filter(filter)
      .middlewareOptions(prepScopes(scopes))
      .headers({"X-PeopleQuery-QuerySources": "Mailbox,Directory"})
      .get();

and graph.user.ts

batch.get(personQuery, `/me/people?$search="${personQuery}"`, ['people.read'], {"X-PeopleQuery-QuerySources": "Mailbox,Directory"});

I'm not sure if it will affect anything else though...

FredrikEkstroem avatar Jul 04 '22 14:07 FredrikEkstroem

Hello FredrikEkstroem, thank you for opening an issue with us!

I have automatically added a "needs triage" label to help get things started. Our team will analyze and investigate the issue, and escalate it to the relevant team if possible. Other community members may also look into the issue and provide feedback 🙌

ghost avatar Jul 04 '22 14:07 ghost

Wow. Today I learnt something new, thanks @FredrikEkstroem!

I think there is some value in having the "regular" headerless query, but I'd love to allow more granularity for some of our components. For the PeoplePicker specifically, do you think having something like this would be useful?

<PeoplePicker
  className={styles.pickerControl}
  selectionMode="single"
  querySources={['Mailbox', 'Directory']}
  consistencyLevel={'Eventual'}
  ref={user}
/>

By default, querySources would not be set and set only when specified. Same for consistencyLevel.

sebastienlevert avatar Jul 04 '22 16:07 sebastienlevert

Keeping it as is by default might be a good idea not to introduce changes in behaviour for people doing upgrades and also makes it more simple if you don't want to send a header, on the other hand the way query sources and consistency level is specified above I believe is how most people think the component work today. The ootb SharePoint people picker today sends query sources, but not consistency level. I think I could go both ways.

Another more flexible way, but maybe not as simple if you use the component for the first time would be to just allow specifying of the headers you want directly, like

<PeoplePicker
  className={styles.pickerControl}
  selectionMode="single"
  headers={{"X-PeopleQuery-QuerySources": "Mailbox,Directory", "consistencyLevel": "Eventual"}}
  ref={user}
/>

or even allowing for both approaches

FredrikEkstroem avatar Jul 05 '22 08:07 FredrikEkstroem

I'm leaning towards setting your own headers attribute. This reduces the number of attributes to keep track of and it is even easier on the backend as you can set all the required headers once.

musale avatar Jul 06 '22 10:07 musale

What happens when we have multiple endpoints called by a single component? We send the headers to all the calls? Hoping they don't fail? That's my only concern.

I'd love to offer headers on all components to help dev drive the behavior of the endpoints, so it's actually a really great proposal @FredrikEkstroem

sebastienlevert avatar Jul 06 '22 15:07 sebastienlevert

@sebastienlevert are you concerned because People Picker calls either /me/people or /users, depending on the settings (I haven't checked this myself, just basing this on what I've read in the mgt docs here. If that's the case, maybe there could also be an attribute to specify which 'user' endpoint you want to use?

HiltonGiesenow avatar Jul 08 '22 12:07 HiltonGiesenow

I've been looking a bit at the code now, and from what I can see, the code's pretty clear on which endpoint it's calling. For instance, at https://github.com/microsoftgraph/microsoft-graph-toolkit/blob/5709ebd27d5cf2b107cccca43e3339a294df38ea/packages/mgt-components/src/graph/graph.user.ts#L53, the method knows it's calling '/users' and at https://github.com/microsoftgraph/microsoft-graph-toolkit/blob/ae546e25d0f4e8bbcd1ebab974a7e3ca04c8e819/packages/mgt-components/src/graph/graph.people.ts#L142 it knows it's calling '/me/people'. What I mean is, there's no if [x] then call this endpoint, otherwise call this one. This means we don't need to have mixed headers, that might not apply to the situation - when one endpoint is used, we can add the headers that it needs very easily, and similarly for the other endpoint.

Aside from that, there's an argument to be made for just doing the 'right' thing - as @FredrikEkstroem said above, this is actually the way people -probably- think it's working today anyway - it was a nasty surprise recently for me when it wasn't, and was excluding certain users. If we don't want to make it the default, because we don't want to break existing codebases, I want to suggest it should be a pretty obvious switch on the controls, for example (bad example but...) "search-depth" or "search-visility", with options like 'only relevant' and 'entire directory'.

I'm happy to work on this, by the way...

HiltonGiesenow avatar Jul 09 '22 19:07 HiltonGiesenow

In this specific example with the people picker (my main concern at the moment) I'm more leaning towards setting a default value since that's how people think it works. Allowing for sending in any custom value to overwrite the default headers would be more flexible so if there are more headers in the future, it's just to send that in, no need to upgrade your mgt version.

Something like below

/** Headers default for this call */
const defaultHeaders:{[header: string]: string;} = {"X-PeopleQuery-QuerySources": "Mailbox,Directory"};
/** default headers merged with user defined headers */
const headers:{[header: string]: string;} = userDefinedHeaders ?? {...defaultHeaders, ...userDefinedHeaders} : defaultHeaders;

To make it easier when coding I would also suggest adding comments to the type definition to describe how it should be used, maybe also a description of what the default value is, something like below

export type PeoplePickerProps = {
	/** Default value: xxxxx. 
	 * Used to send in extra headers to the graph call
	 * Example:
	 * {"consistencyLevel": "Eventual"}
	 */
	headers?:{[header: string]: string;}
	...
}

I'm not 100% sure I found the right place in the code, but might be here mgt-react\src\generated\react.ts? Or are those autogenerated some way?

FredrikEkstroem avatar Jul 11 '22 12:07 FredrikEkstroem

@FredrikEkstroem sorry for the late reply. Yes, the react files are auto generated.

musale avatar Jul 25 '22 12:07 musale

@FredrikEkstroem Can you confirm that v2.6.2 solved this issue? @HiltonGiesenow provided a great PR for this topic! Thanks!

sebastienlevert avatar Oct 24 '22 19:10 sebastienlevert

This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 4 days. It will be closed if no further activity occurs within 3 days of this comment.

ghost avatar Oct 28 '22 20:10 ghost