feat: Implement SharePoint People Picker for selecting starting person and update version to 1.0.3
This commit is contained in:
@@ -11,6 +11,7 @@ import {
|
||||
} from './OrganizationChartCore';
|
||||
import {
|
||||
IOrganizationChartData,
|
||||
IOrganizationChartPersonSuggestion,
|
||||
IOrganizationNode,
|
||||
IUserProfile,
|
||||
IUserProfileProperty
|
||||
@@ -35,6 +36,7 @@ interface IPeoplePickerEntityData {
|
||||
}
|
||||
|
||||
interface IPeoplePickerEntity {
|
||||
DisplayText?: string;
|
||||
EntityData?: IPeoplePickerEntityData;
|
||||
IsResolved?: boolean;
|
||||
Key?: string;
|
||||
@@ -49,7 +51,8 @@ export class OrganizationChartDataService {
|
||||
accountName: string,
|
||||
maxDepth: number,
|
||||
maxPeople: number,
|
||||
cacheMinutes: number
|
||||
cacheMinutes: number,
|
||||
alternateAccountName?: string
|
||||
): Promise<IOrganizationChartData> {
|
||||
const account: string = normalizeAccount(accountName);
|
||||
const state: ITreeLoadState = {
|
||||
@@ -60,7 +63,7 @@ export class OrganizationChartDataService {
|
||||
visited: {}
|
||||
};
|
||||
const rootRequest: Promise<IUserProfile> = account
|
||||
? this.getConfiguredProfile(account, cacheMinutes)
|
||||
? this.getConfiguredProfile(account, cacheMinutes, alternateAccountName)
|
||||
: this.getMyProfile(cacheMinutes);
|
||||
return rootRequest
|
||||
.then((profile: IUserProfile): Promise<IOrganizationNode> =>
|
||||
@@ -94,11 +97,39 @@ export class OrganizationChartDataService {
|
||||
return this.requestProfile(url, key, cacheMinutes);
|
||||
}
|
||||
|
||||
private getConfiguredProfile(accountName: string, cacheMinutes: number): Promise<IUserProfile> {
|
||||
public searchPeople(query: string): Promise<IOrganizationChartPersonSuggestion[]> {
|
||||
const searchText: string = normalizeAccount(query);
|
||||
if (searchText.length < 2) { return Promise.resolve([]); }
|
||||
return this.requestPeoplePicker(searchText).then(
|
||||
(entities: IPeoplePickerEntity[]): IOrganizationChartPersonSuggestion[] =>
|
||||
entities.filter((entity: IPeoplePickerEntity): boolean =>
|
||||
entity.IsResolved !== false && !!normalizeAccount(entity.Key))
|
||||
.map((entity: IPeoplePickerEntity): IOrganizationChartPersonSuggestion => ({
|
||||
accountName: normalizeAccount(entity.EntityData && entity.EntityData.AccountName),
|
||||
displayName: normalizeAccount(entity.DisplayText) || normalizeAccount(entity.Key),
|
||||
email: normalizeAccount(entity.EntityData && entity.EntityData.Email),
|
||||
loginName: normalizeAccount(entity.Key)
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
public validatePerson(loginName: string, accountName: string, cacheMinutes: number): Promise<boolean> {
|
||||
const candidates: string[] = uniqueAccounts([loginName, accountName], '', 2);
|
||||
return this.getFirstAvailableProfile(candidates, cacheMinutes, 0)
|
||||
.then((): boolean => true, (): boolean => false);
|
||||
}
|
||||
|
||||
private getConfiguredProfile(
|
||||
accountName: string,
|
||||
cacheMinutes: number,
|
||||
alternateAccountName?: string
|
||||
): Promise<IUserProfile> {
|
||||
return this.resolveAccountNames(accountName)
|
||||
.catch((): string[] => [accountName])
|
||||
.then((accounts: string[]): Promise<IUserProfile> =>
|
||||
this.getFirstAvailableProfile(accounts, cacheMinutes, 0));
|
||||
.then((accounts: string[]): Promise<IUserProfile> => {
|
||||
const candidates: string[] = uniqueAccounts(accounts.concat([alternateAccountName]), '', accounts.length + 1);
|
||||
return this.getFirstAvailableProfile(candidates, cacheMinutes, 0);
|
||||
});
|
||||
}
|
||||
|
||||
private getFirstAvailableProfile(
|
||||
@@ -116,6 +147,29 @@ export class OrganizationChartDataService {
|
||||
}
|
||||
|
||||
private resolveAccountNames(accountName: string): Promise<string[]> {
|
||||
return this.searchPeople(accountName).then(
|
||||
(suggestions: IOrganizationChartPersonSuggestion[]): string[] => {
|
||||
const input: string = normalizeAccount(accountName).toLowerCase();
|
||||
const matching: IOrganizationChartPersonSuggestion[] = suggestions.filter(
|
||||
(suggestion: IOrganizationChartPersonSuggestion): boolean =>
|
||||
suggestion.accountName.toLowerCase() === input ||
|
||||
suggestion.email.toLowerCase() === input ||
|
||||
suggestion.loginName.toLowerCase() === input
|
||||
);
|
||||
const selected: IOrganizationChartPersonSuggestion[] = matching.length
|
||||
? matching
|
||||
: (suggestions.length === 1 ? suggestions : []);
|
||||
const candidates: string[] = [];
|
||||
selected.forEach((suggestion: IOrganizationChartPersonSuggestion): void => {
|
||||
candidates.push(suggestion.loginName);
|
||||
candidates.push(suggestion.accountName);
|
||||
});
|
||||
candidates.push(normalizeAccount(accountName));
|
||||
return uniqueAccounts(candidates, '', candidates.length || 1);
|
||||
});
|
||||
}
|
||||
|
||||
private requestPeoplePicker(accountName: string): Promise<IPeoplePickerEntity[]> {
|
||||
const url: string = this.webUrl +
|
||||
'/_api/SP.UI.ApplicationPages.ClientPeoplePickerWebServiceInterface.clientPeoplePickerSearchUser';
|
||||
const body: string = JSON.stringify({
|
||||
@@ -140,30 +194,14 @@ export class OrganizationChartDataService {
|
||||
if (response.ok) { return response.json(); }
|
||||
return response.text().then((text: string): Promise<any> => // tslint:disable-line:no-any
|
||||
Promise.reject(new Error('People Picker request failed (' + response.status + '): ' + text)));
|
||||
}).then((payload: any): string[] => { // tslint:disable-line:no-any
|
||||
}).then((payload: any): IPeoplePickerEntity[] => { // tslint:disable-line:no-any
|
||||
const data: any = payload && payload.d !== undefined ? payload.d : payload; // tslint:disable-line:no-any
|
||||
const serialized: string = String(
|
||||
data && data.ClientPeoplePickerSearchUser !== undefined
|
||||
? data.ClientPeoplePickerSearchUser
|
||||
: (data && data.value !== undefined ? data.value : '[]')
|
||||
);
|
||||
let entities: IPeoplePickerEntity[] = [];
|
||||
try { entities = JSON.parse(serialized) as IPeoplePickerEntity[]; } catch (error) { entities = []; }
|
||||
const input: string = normalizeAccount(accountName).toLowerCase();
|
||||
const matching: IPeoplePickerEntity[] = entities.filter((entity: IPeoplePickerEntity): boolean => {
|
||||
const account: string = normalizeAccount(entity.EntityData && entity.EntityData.AccountName).toLowerCase();
|
||||
const email: string = normalizeAccount(entity.EntityData && entity.EntityData.Email).toLowerCase();
|
||||
const key: string = normalizeAccount(entity.Key).toLowerCase();
|
||||
return entity.IsResolved !== false && (account === input || email === input || key === input);
|
||||
});
|
||||
const selected: IPeoplePickerEntity[] = matching.length ? matching : (entities.length === 1 ? entities : []);
|
||||
const candidates: string[] = [];
|
||||
selected.forEach((entity: IPeoplePickerEntity): void => {
|
||||
candidates.push(normalizeAccount(entity.Key));
|
||||
candidates.push(normalizeAccount(entity.EntityData && entity.EntityData.AccountName));
|
||||
});
|
||||
candidates.push(normalizeAccount(accountName));
|
||||
return uniqueAccounts(candidates, '', candidates.length || 1);
|
||||
try { return JSON.parse(serialized) as IPeoplePickerEntity[]; } catch (error) { return []; }
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user