This commit is contained in:
petkir 2020-07-19 22:11:52 +02:00
parent 36133a9c2b
commit 709256f784
7 changed files with 351 additions and 59 deletions

View File

@ -1,9 +1,7 @@
import { PeoplePickerEntity } from '@pnp/sp'; import { PeoplePickerEntity } from '@pnp/sp';
export interface ISPServices { export interface ISPServices {
getUserProperties(user: string): Promise<any>;
getUserProfileProperty(user: string, property: string): Promise<string>;
getUsers(searchUser: string): Promise<PeoplePickerEntity[]>;
searchUsers(searchString: string, searchFirstName: boolean); searchUsers(searchString: string, searchFirstName: boolean);
} }

View File

@ -0,0 +1,210 @@
{
"odata.metadata": "https://contoso.sharepoint.com/_api/$metadata#Microsoft.Office.Server.Search.REST.SearchResult",
"ElapsedTime": 34,
"PrimaryQueryResult": {
"CustomResults": [],
"QueryId": "70699796-a977-4437-b771-92a074e322e6",
"QueryRuleId": "00000000-0000-0000-0000-000000000000",
"RefinementResults": null,
"RelevantResults": {
"GroupTemplateId": null,
"ItemTemplateId": null,
"Properties": [],
"ResultTitle": null,
"ResultTitleUrl": null,
"RowCount": 1,
"Table": {
"Rows": [{
"Cells": [{
"Key": "Rank",
"Value": "0",
"ValueType": "Edm.Double"
}, {
"Key": "DocId",
"Value": "17646696630634",
"ValueType": "Edm.Int64"
}, {
"Key": "FirstName",
"Value": "Peter Paul",
"ValueType": "Edm.String"
}, {
"Key": "LastName",
"Value": "Kirschner",
"ValueType": "Edm.String"
}, {
"Key": "PreferredName",
"Value": "Peter Paul Kirschner",
"ValueType": "Edm.String"
}, {
"Key": "WorkEmail",
"Value": "petkir@pkirschner.onmicrosoft.com",
"ValueType": "Edm.String"
}, {
"Key": "OfficeNumber",
"Value": null,
"ValueType": "Null"
}, {
"Key": "PictureURL",
"Value": "",
"ValueType": "Edm.String"
}, {
"Key": "WorkPhone",
"Value": "4250000000",
"ValueType": "Edm.String"
}, {
"Key": "MobilePhone",
"Value": null,
"ValueType": "Null"
}, {
"Key": "JobTitle",
"Value": null,
"ValueType": "Null"
}, {
"Key": "Department",
"Value": null,
"ValueType": "Null"
}, {
"Key": "Skills",
"Value": "",
"ValueType": "Edm.String"
}, {
"Key": "PastProjects",
"Value": "",
"ValueType": "Edm.String"
}, {
"Key": "BaseOfficeLocation",
"Value": null,
"ValueType": "Null"
}, {
"Key": "SPS-UserType",
"Value": "0",
"ValueType": "Edm.Int64"
}, {
"Key": "GroupId",
"Value": null,
"ValueType": "Null"
}, {
"Key": "SiteId",
"Value": null,
"ValueType": "Null"
}, {
"Key": "WebId",
"Value": null,
"ValueType": "Null"
}, {
"Key": "UniqueId",
"Value": null,
"ValueType": "Null"
}, {
"Key": "contentclass",
"Value": "urn:content-class:SPSPeople",
"ValueType": "Edm.String"
}, {
"Key": "PartitionId",
"Value": "92ab9c96-469b-4d78-8b8c-961c4df9356b",
"ValueType": "Edm.Guid"
}, {
"Key": "UrlZone",
"Value": "0",
"ValueType": "Edm.Int32"
}, {
"Key": "Culture",
"Value": "en-US",
"ValueType": "Edm.String"
}, {
"Key": "ResultTypeId",
"Value": "0",
"ValueType": "Edm.Int32"
}, {
"Key": "EditProfileUrl",
"Value": null,
"ValueType": "Null"
}, {
"Key": "ProfileViewsLastMonth",
"Value": null,
"ValueType": "Null"
}, {
"Key": "ProfileViewsLastWeek",
"Value": null,
"ValueType": "Null"
}, {
"Key": "ProfileQueriesFoundYou",
"Value": null,
"ValueType": "Null"
}, {
"Key": "RenderTemplateId",
"Value": "~sitecollection/_catalogs/masterpage/Display Templates/Search/Item_Default.js",
"ValueType": "Edm.String"
}, {
"Key": "GeoLocationSource",
"Value": "EUR",
"ValueType": "Edm.String"
}]
}]
},
"TotalRows": 1,
"TotalRowsIncludingDuplicates": 1
},
"SpecialTermResults": null
},
"Properties": [{
"Key": "RowLimit",
"Value": "500",
"ValueType": "Edm.Int32"
}, {
"Key": "SourceId",
"Value": "b09a7990-05ea-4af9-81ef-edfab16c4e31",
"ValueType": "Edm.Guid"
}, {
"Key": "CorrelationId",
"Value": "e83b679f-b0c6-2000-3de3-321f0ebd7f6d",
"ValueType": "Edm.Guid"
}, {
"Key": "WasGroupRestricted",
"Value": "false",
"ValueType": "Edm.Boolean"
}, {
"Key": "WordBreakerLanguage",
"Value": "default",
"ValueType": "Edm.String"
}, {
"Key": "IsPartialUpnDocIdMapping",
"Value": "false",
"ValueType": "Edm.Boolean"
}, {
"Key": "EnableInterleaving",
"Value": "true",
"ValueType": "Edm.Boolean"
}, {
"Key": "IsMissingUnifiedGroups",
"Value": "false",
"ValueType": "Edm.Boolean"
}, {
"Key": "Constellation",
"Value": "i31EEE",
"ValueType": "Edm.String"
}, {
"Key": "MultiGeoSearchStatus",
"Value": "Full",
"ValueType": "Edm.String"
}, {
"Key": "HasParseException",
"Value": "false",
"ValueType": "Edm.Boolean"
}, {
"Key": "IsPartial",
"Value": "false",
"ValueType": "Edm.Boolean"
}, {
"Key": "InternalRequestId",
"Value": "e44dc9d5-b4dc-4f4e-84f1-eef4eb163ad4",
"ValueType": "Edm.String"
}, {
"Key": "SerializedQuery",
"Value": "<Query Culture=\"en-US\" EnableStemming=\"True\" EnablePhonetic=\"False\" EnableNicknames=\"False\" IgnoreAllNoiseQuery=\"True\" SummaryLength=\"180\" MaxSnippetLength=\"180\" DesiredSnippetLength=\"90\" KeywordInclusion=\"0\" QueryText=\"LastName:kir*\" QueryTemplate=\"\" TrimDuplicates=\"True\" Site=\"3ea90dc6-5d70-4967-80a0-e07cbae5867f\" Web=\"ea51dacc-87ca-49cd-9f28-13fd2cb3b96b\" KeywordType=\"True\" HiddenConstraints=\"\" />",
"ValueType": "Edm.String"
}],
"SecondaryQueryResults": [],
"SpellingSuggestion": null,
"TriggeredRules": []
}

View File

@ -0,0 +1,112 @@
import { ISPServices } from "./ISPServices";
import * as mockdata from './MockDataSearch.json';
import { cloneDeep } from '@microsoft/sp-lodash-subset';
interface MinimalMockUser {
FirstName: string;
LastName: string;
Department: string;
Location: string;
Title: string;
PreferredName: string;
WorkPhone: string;
}
/*
DisplayName: user.PreferredName,
Title: user.JobTitle,
PictureUrl: user.PictureURL,
Email: user.WorkEmail,
Department: user.Department,
WorkPhone: user.WorkPhone,
Location: user.OfficeNumber
? user.OfficeNumber
: user.BaseOfficeLocation
*/
const sampleUserFirstNameLetter: string[] = [
"A",
"C",
"D",
"F",
"H",
"J",
"L",
"N",
"P",
"R",
"T",
"V",
"X",
"Z",
];
const sampleUserLastNameLetter: string[] = [
"B",
"E",
"G",
"I",
"K",
"M",
"O",
"Q",
"S",
"U",
"W",
"Y",
];
export class spMockServices implements ISPServices {
private sampleData: MinimalMockUser[] = [];
constructor() {
sampleUserLastNameLetter.forEach(lastNameL => {
sampleUserFirstNameLetter.forEach(firstNameL => {
const usercount = Math.floor(Math.random() * (5)) + 1;
for (let i = 0; i < usercount; i++) {
this.sampleData.push({
FirstName: `${firstNameL}FirstName${i}`,
LastName: `${lastNameL}LastName${i}`,
PreferredName: `${firstNameL}FirstName${i} ${lastNameL}LastName${i}`,
Department: i % 2 === 0 ? `${lastNameL}Department` : `${firstNameL}Department`,
Location: i % 3 === 0 ? `${lastNameL}Location` : `${firstNameL}Location`,
Title: i % 2 === 0 ? `${lastNameL}JobTitle` : `${firstNameL}JobTitle`,
WorkPhone: '' + Math.floor(Math.random() * 1234) + 54678900
});
}
});
});
}
public async searchUsers(searchString: string, searchFirstName: boolean) {
let filtervalue = searchString.trim().toLowerCase();
if (searchString.length > 0 && filtervalue.lastIndexOf("*") == searchString.length - 1) {
// remove last '*'
filtervalue = filtervalue.substring(0, searchString.length - 1);
}
if (!filtervalue || filtervalue.length === 0) {
throw new Error("No valid Input.");
}
const searchresult = !!searchFirstName ?
this.sampleData.filter(p => p.FirstName.toLowerCase().indexOf(filtervalue) === 0) :
this.sampleData.filter(p => p.LastName.toLowerCase().indexOf(filtervalue) === 0);
const timeout = Math.floor(Math.random() * (1000)) + 1;
const resultdata = {
ElapsedTime: timeout,
RowCount: searchresult.length,
TotalRows: searchresult.length,
PrimarySearchResults: searchresult
};
return new Promise((resolve) => {
setTimeout(() => {
resolve(resultdata);
}, timeout);
});
}
}

View File

@ -18,51 +18,15 @@ export class spservices implements ISPServices {
}); });
} }
public async getUserProperties(user: string): Promise<any> {
try { public async searchUsers(searchString: string, searchFirstName: boolean): Promise<SearchResults> {
let currentUserProperties: any = await sp.profiles.getPropertiesFor(user); const _search = !searchFirstName ? `LastName:${searchString}*` : `FirstName:${searchString}*`;
return currentUserProperties; const searchProperties: string[] = ["FirstName", "LastName", "PreferredName", "WorkEmail", "OfficeNumber", "PictureURL", "WorkPhone", "MobilePhone", "JobTitle", "Department", "Skills", "PastProjects", "BaseOfficeLocation", "SPS-UserType", "GroupId"];
} catch (error) {
Promise.reject(error);
}
}
/**
* async GetUserProfileProperty
user:string */
public async getUserProfileProperty(user: string, property: string): Promise<string> {
try {
let UserProperty: string = await sp.profiles.getUserProfilePropertyFor(user, property);
console.log(UserProperty);
return UserProperty;
} catch (error) {
Promise.reject(error);
}
}
/**
*
* @param {string} searchUser
* @memberof spservices
*/
public async getUsers(searchUser: string): Promise<PeoplePickerEntity[]> {
try {
let users: PeoplePickerEntity[] = await sp.profiles.clientPeoplePickerSearchUser({ QueryString: searchUser, MaximumEntitySuggestions: 100, PrincipalType: 1 });
return users;
} catch (error) {
Promise.reject(error);
}
}
public async searchUsers(searchString: string, searchFirstName:boolean) {
const _search = !searchFirstName ? `LastName:${searchString}*` : `FirstName:${searchString}*` ;
const searchProperties: string[] = ["FirstName", "LastName", "PreferredName", "WorkEmail", "OfficeNumber","PictureURL", "WorkPhone", "MobilePhone", "JobTitle", "Department", "Skills", "PastProjects", "BaseOfficeLocation", "SPS-UserType","GroupId"];
try { try {
if (!searchString) return undefined; if (!searchString) return undefined;
let users = await sp.searchWithCaching(<SearchQuery>{ let users = await sp.searchWithCaching(<SearchQuery>{
Querytext: _search, Querytext: _search,
RowLimit:500, RowLimit: 500,
EnableInterleaving: true, EnableInterleaving: true,
SelectProperties: searchProperties, SelectProperties: searchProperties,
SourceId: 'b09a7990-05ea-4af9-81ef-edfab16c4e31', SourceId: 'b09a7990-05ea-4af9-81ef-edfab16c4e31',

View File

@ -23,6 +23,8 @@ import {
import { WebPartTitle } from "@pnp/spfx-controls-react/lib/WebPartTitle"; import { WebPartTitle } from "@pnp/spfx-controls-react/lib/WebPartTitle";
import { ISPServices } from "../../../SPServices/ISPServices"; import { ISPServices } from "../../../SPServices/ISPServices";
import { Environment, EnvironmentType } from "@microsoft/sp-core-library";
import { spMockServices } from "../../../SPServices/spMockServices";
const az: string[] = [ const az: string[] = [
"A", "A",
@ -77,13 +79,16 @@ export default class Directory extends React.Component<
searchString: "LastName", searchString: "LastName",
searchText: "" searchText: ""
}; };
if (Environment.type === EnvironmentType.Local) {
this._services = new spMockServices();
} else {
this._services = new spservices(this.props.context); this._services = new spservices(this.props.context);
}
// Register event handlers // Register event handlers
this._searchUsers = this._searchUsers.bind(this); this._searchUsers = this._searchUsers.bind(this);
this._selectedIndex = this._selectedIndex.bind(this); this._selectedIndex = this._selectedIndex.bind(this);
this._sortPeople = this._sortPeople.bind(this); this._sortPeople = this._sortPeople.bind(this);
this._searchBoxChanged = this._searchBoxChanged.bind(this) this._searchBoxChanged = this._searchBoxChanged.bind(this);
} }
/** /**
@ -137,7 +142,7 @@ export default class Directory extends React.Component<
searchText, searchText,
this.props.searchFirstName this.props.searchFirstName
); );
debugger;
if (users && users.PrimarySearchResults.length > 0) { if (users && users.PrimarySearchResults.length > 0) {
for (let index = 0; index < users.PrimarySearchResults.length; index++) { for (let index = 0; index < users.PrimarySearchResults.length; index++) {
let user: any = users.PrimarySearchResults[index]; let user: any = users.PrimarySearchResults[index];

View File

@ -3,7 +3,7 @@ import styles from './PersonaCard.module.scss';
import { IPersonaCardProps } from './IPersonaCardProps'; import { IPersonaCardProps } from './IPersonaCardProps';
import { IPersonaCardState } from './IPersonaCardState'; import { IPersonaCardState } from './IPersonaCardState';
import { import {
Log, Log, Environment, EnvironmentType,
} from '@microsoft/sp-core-library'; } from '@microsoft/sp-core-library';
import { SPComponentLoader } from '@microsoft/sp-loader'; import { SPComponentLoader } from '@microsoft/sp-loader';
@ -22,7 +22,7 @@ const LIVE_PERSONA_COMPONENT_ID: string =
export class PersonaCard extends React.Component< export class PersonaCard extends React.Component<
IPersonaCardProps, IPersonaCardProps,
IPersonaCardState IPersonaCardState
> { > {
constructor(props: IPersonaCardProps) { constructor(props: IPersonaCardProps) {
super(props); super(props);
@ -34,12 +34,14 @@ export class PersonaCard extends React.Component<
* @memberof PersonaCard * @memberof PersonaCard
*/ */
public async componentDidMount() { public async componentDidMount() {
const sharedLibrary = await this._loadSPComponentById( if (Environment.type !== EnvironmentType.Local) {
LIVE_PERSONA_COMPONENT_ID const sharedLibrary = await this._loadSPComponentById(
); LIVE_PERSONA_COMPONENT_ID
const livePersonaCard: any = sharedLibrary.LivePersonaCard; );
console.log(livePersonaCard); const livePersonaCard: any = sharedLibrary.LivePersonaCard;
this.setState({ livePersonaCard: livePersonaCard }); console.log(livePersonaCard);
this.setState({ livePersonaCard: livePersonaCard });
}
} }
/** /**
@ -52,7 +54,7 @@ export class PersonaCard extends React.Component<
public componentDidUpdate( public componentDidUpdate(
prevProps: IPersonaCardProps, prevProps: IPersonaCardProps,
prevState: IPersonaCardState prevState: IPersonaCardState
): void {} ): void { }
/** /**
* *
@ -110,8 +112,8 @@ export class PersonaCard extends React.Component<
</span> </span>
</div> </div>
) : ( ) : (
'' ''
)} )}
{this.props.profileProperties.Location ? ( {this.props.profileProperties.Location ? (
<div> <div>
<Icon iconName="Poi" style={{ fontSize: '12px' }} /> <Icon iconName="Poi" style={{ fontSize: '12px' }} />
@ -121,8 +123,8 @@ export class PersonaCard extends React.Component<
</span> </span>
</div> </div>
) : ( ) : (
'' ''
)} )}
</Persona> </Persona>
</div> </div>
</DocumentCard> </DocumentCard>

View File

@ -5,6 +5,7 @@
"forceConsistentCasingInFileNames": true, "forceConsistentCasingInFileNames": true,
"module": "esnext", "module": "esnext",
"moduleResolution": "node", "moduleResolution": "node",
"resolveJsonModule" : true,
"jsx": "react", "jsx": "react",
"declaration": true, "declaration": true,
"sourceMap": true, "sourceMap": true,