Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: people picker state management #2028

Merged
merged 1 commit into from
Feb 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,6 @@
"embeddedLanguageFormatting": "off"
},
"resolutions": {
"react": "16.13.1",
"react-dom": "16.13.1",
"responselike": "2.0.0"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,13 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
return styles;
}

/**
* The strings to be used for localizing the component.
*
* @readonly
* @protected
* @memberof MgtPeoplePicker
*/
protected get strings() {
return strings;
}
Expand Down Expand Up @@ -229,6 +236,13 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
this.requestStateUpdate(true);
}

/**
* The type of user to search for. Default is any.
*
* @readonly
* @type {UserType}
* @memberof MgtPeoplePicker
*/
@property({
attribute: 'user-type',
converter: (value, type) => {
Expand Down Expand Up @@ -264,7 +278,15 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
attribute: 'transitive-search',
type: Boolean
})
public transitiveSearch: boolean;
public get transitiveSearch(): boolean {
return this._transitiveSearch;
}
public set transitiveSearch(value: boolean) {
if (this.transitiveSearch !== value) {
this._transitiveSearch = value;
this.requestStateUpdate(true);
}
}

/**
* containing object of IDynamicPerson.
Expand All @@ -274,7 +296,15 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
attribute: 'people',
type: Object
})
public people: IDynamicPerson[];
public get people(): IDynamicPerson[] {
return this._people;
}
public set people(value: IDynamicPerson[]) {
if (!arraysAreEqual(this._people, value)) {
this._people = value;
this.requestStateUpdate(true);
}
}

/**
* determining how many people to show in list.
Expand All @@ -284,7 +314,15 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
attribute: 'show-max',
type: Number
})
public showMax: number;
public get showMax(): number {
return this._showMax;
}
public set showMax(value: number) {
if (value !== this._showMax) {
this._showMax = value;
this.requestStateUpdate(true);
}
}

/**
* Sets whether the person image should be fetched
Expand All @@ -300,17 +338,25 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
public disableImages: boolean;

/**
* array of user picked people.
* array of user picked people.
* @type {IDynamicPerson[]}
*/
@property({
attribute: 'selected-people',
type: Array
})
public selectedPeople: IDynamicPerson[];
public get selectedPeople(): IDynamicPerson[] {
return this._selectedPeople;
}
public set selectedPeople(value: IDynamicPerson[]) {
if (!value) value = [];
if (!arraysAreEqual(this._selectedPeople, value)) {
this._selectedPeople = value;
}
}

/**
* array of people to be selected upon intialization
* array of people to be selected upon initialization
*
* @type {string[]}
* @memberof MgtPeoplePicker
Expand All @@ -322,10 +368,18 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
},
type: String
})
public defaultSelectedUserIds: string[];
public get defaultSelectedUserIds(): string[] {
return this._defaultSelectedUserIds;
}
public set defaultSelectedUserIds(value) {
if (!arraysAreEqual(this._defaultSelectedUserIds, value)) {
this._defaultSelectedUserIds = value;
this.requestStateUpdate(true);
}
}

/**
* array of groups to be selected upon intialization
* array of groups to be selected upon initialization
*
* @type {string[]}
* @memberof MgtPeoplePicker
Expand All @@ -337,7 +391,15 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
},
type: String
})
public defaultSelectedGroupIds: string[];
public get defaultSelectedGroupIds(): string[] {
return this._defaultSelectedGroupIds;
}
public set defaultSelectedGroupIds(value) {
if (!arraysAreEqual(this._defaultSelectedGroupIds, value)) {
this._defaultSelectedGroupIds = value;
this.requestStateUpdate(true);
}
}

/**
* Placeholder text.
Expand Down Expand Up @@ -387,7 +449,6 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
})
public selectionMode: string;

private _userIds: string[];
/**
* Array of the only users to be searched.
*
Expand Down Expand Up @@ -484,8 +545,9 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
protected userInput: string;

// if search is still loading don't load "people not found" state
@property({ attribute: false }) private _showLoading: boolean;
@state() private _showLoading: boolean;

private _userIds: string[];
private _groupId: string;
private _groupIds: string[];
private _type: PersonType = PersonType.person;
Expand All @@ -494,6 +556,12 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
private _userFilters: string;
private _groupFilters: string;
private _peopleFilters: string;
private _defaultSelectedGroupIds: string[];
private _defaultSelectedUserIds: string[];
private _selectedPeople: IDynamicPerson[] = [];
private _showMax: number;
private _people: IDynamicPerson[];
private _transitiveSearch: boolean;

private defaultPeople: IDynamicPerson[];

Expand Down Expand Up @@ -674,7 +742,7 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
* @memberof MgtPeoplePicker
*/
protected renderInput(): TemplateResult {
const hasSelectedPeople = !!this.selectedPeople.length;
const hasSelectedPeople = this.selectedPeople?.length > 0;

const placeholder = !this.disabled
? this.placeholder
Expand Down Expand Up @@ -1051,7 +1119,7 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
this._showLoading = false;

if (
(this.defaultSelectedUserIds || this.defaultSelectedGroupIds) &&
(this.defaultSelectedUserIds?.length > 0 || this.defaultSelectedGroupIds?.length > 0) &&
!this.selectedPeople.length &&
!this.defaultSelectedUsers
) {
Expand Down Expand Up @@ -1148,7 +1216,7 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
}
}
} catch (e) {
// nop
// no-op
}
}
}
Expand All @@ -1164,7 +1232,9 @@ export class MgtPeoplePicker extends MgtTemplatedComponent {
this.groupType,
this.userFilters
);
} catch (_) {}
} catch (_) {
// no-op
}
} else {
let groups = [];
try {
Expand Down
94 changes: 60 additions & 34 deletions samples/react-app/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { Component, useRef } from 'react';
import React, { useEffect, useRef, useState } from 'react';
import {
Login,
Agenda,
Expand All @@ -12,44 +12,70 @@ import {
import * as MicrosoftGraph from '@microsoft/microsoft-graph-types';
import { MgtPerson } from '@microsoft/mgt-components';

class App extends Component {
handleTemplateRendered = (e: Event) => {
const personDetails = {
displayName: 'Nikola Metulev',
mail: '[email protected]'
};
function sleep(ms: number) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
const App = () => {
const [userIds, setUserIds] = useState<any[]>([]);

useEffect(() => {
const load = async () => {
await sleep(2500);

const ids = [];
ids.push('87d349ed-44d7-43e1-9a83-5f2406dee5bd');
ids.push('5bde3e51-d13b-4db1-9948-fe4b109d11a7');
ids.push('[email protected]');
setUserIds(ids);
};
void load();
}, []);

const handleTemplateRendered = (e: Event) => {
console.log('Event Rendered: ', e);
};

render() {
const personDetails = {
displayName: 'Nikola Metulev',
mail: '[email protected]'
};
const handleSelectionChanged = (e: any) => {
// setSelectedPeople(e.detail);
console.log('e.detail: ', e.detail);
};

return (
<div className="App">
<Login loginCompleted={() => console.log('login completed')} />
<Agenda groupByDay templateRendered={this.handleTemplateRendered}>
<MyEvent template="event" />
</Agenda>
return (
<div className='App'>
<Login loginCompleted={() => console.log('login completed')} />

<Person
personDetails={personDetails}
view={PersonViewType.twolines}
className="my-class"
onClick={() => console.log('person clicked')}
line2clicked={() => console.log('line1 clicked')}
/>

<PeoplePicker type={PersonType.any} />

<Get resource="/me">
<MyTemplate />
</Get>

<Get resource="/me/messages" scopes={['mail.read']} maxPages={2}>
<MyMessage template="value" />
</Get>
</div>
);
}
<Agenda groupByDay templateRendered={handleTemplateRendered}>
<MyEvent template='event' />
</Agenda>

<Person
personDetails={personDetails}
view={PersonViewType.twolines}
className='my-class'
onClick={() => console.log('person clicked')}
line2clicked={() => console.log('line1 clicked')}
/>

<PeoplePicker
type={PersonType.person}
selectionMode='multiple'
defaultSelectedUserIds={userIds}
selectionChanged={handleSelectionChanged}
/>

<Get resource='/me'>
<MyTemplate />
</Get>

<Get resource='/me/messages' scopes={['mail.read']} maxPages={2}>
<MyMessage template='value' />
</Get>
</div>
);
}

const MyEvent = (props: MgtTemplateProps) => {
Expand Down
17 changes: 17 additions & 0 deletions stories/components/peoplePicker/peoplePicker.properties.js
Original file line number Diff line number Diff line change
Expand Up @@ -307,3 +307,20 @@ export const pickerWithAriaLabel = () => html`
>
</mgt-people-picker>
`;

export const asyncDefaultSelectedUserIds = () => {
return html`

<mgt-people-picker id="async-picker"></mgt-people-picker>
<script type="module">
window.setTimeout(() => {
const userIds = 'e3d0513b-449e-4198-ba6f-bd97ae7cae85,40079818-3808-4585-903b-02605f061225'.split(
','
);
const picker = document.getElementById('async-picker');
picker.defaultSelectedUserIds = userIds;
console.log('defaultSelectedUserIds set');
}, 2000);
</script>
`;
};