Skip to content

Commit 55c92fa

Browse files
committed
Merge branch 'russgove-dev' into dev
2 parents bc369e7 + e288131 commit 55c92fa

File tree

10 files changed

+367
-352
lines changed

10 files changed

+367
-352
lines changed

docs/documentation/docs/controls/ListPicker.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { ListPicker } from "@pnp/spfx-controls-react/lib/ListPicker";
3030
label="Select your list(s)"
3131
placeHolder="Select your list(s)"
3232
baseTemplate={100}
33+
contentTypeId="0x0101"
3334
includeHidden={false}
3435
multiSelect={false}
3536
onSelectionChanged={this.onListPickerChange} />
@@ -56,13 +57,15 @@ The `ListPicker` control can be configured with the following properties:
5657
| filter | string | no | Filter list from OData query (takes precendents over Hidden and BaseTemplate Filters). |
5758
| includeHidden | boolean | no | Whether or not to include hidden lists. Default is `true`. |
5859
| orderBy | LibsOrderBy | no | How to order the lists retrieved from SharePoint. |
59-
| selectedList | string OR string[] | no | Keys of the selected item(s). If you provide this, you must maintain selection state by observing onSelectionChanged events and passing a new value in when changed. |
60+
| selectedList | string OR string[] | no | Keys(list Ids) of the selected item(s). If you provide this, you must maintain selection state by observing onSelectionChanged events and passing a new value in when changed. |
6061
| multiSelect | boolean | no | Optional mode indicates if multi-choice selections is allowed. Default to `false`. |
6162
| label | string | no | Label to use for the control. |
6263
| placeHolder | string | no | Placeholder label to show in the dropdown. **Deprecated. Use `placeholder` instead.** |
6364
| placeholder | string | no | Placeholder label to show in the dropdown. |
6465
| onSelectionChanged | (newValue: string OR string[]): void | no | Callback function when the selected option changes. |
6566
| webAbsoulteUrl | string | no | Absolute Web Url of target site (user requires permissions) |
67+
| contentTypeId | string | no | The Id if a content type which must be present in a list in order for the list to appear in the picker.|
68+
| refreshToggle | boolean | no | If present can be used to force the control to refresh the list of lists by toggling its value|
6669

6770
Enum `LibsOrderBy`
6871

package-lock.json

Lines changed: 251 additions & 297 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/common/SPEntities.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,26 @@
1+
2+
3+
4+
/**
5+
* Represents SP ContentType Id
6+
*/
7+
export interface ISPContentTypeId {
8+
StringValue: string;
9+
}
10+
/**
11+
* Represents SP List ContentType
12+
*/
13+
export interface ISPListContentType {
14+
Id: ISPContentTypeId;
15+
}
116
/**
217
* Represents SP List
318
*/
419
export interface ISPList {
520
Id: string;
621
Title: string;
722
BaseTemplate: string;
23+
ContentTypes? :ISPListContentType[];
824
}
925

1026
/**
@@ -95,7 +111,7 @@ export interface ICultureCalendar {
95111
}
96112

97113
/**
98-
* Replica of Microsoft's DateTimeFormat difinition for CultureInfo object
114+
* Replica of Microsoft's DateTimeFormat definition for CultureInfo object
99115
*/
100116
export interface ICultureDateTimeFormat {
101117
AMDesignator: string;
@@ -128,7 +144,7 @@ export interface ICultureDateTimeFormat {
128144
}
129145

130146
/**
131-
* Replica of Microsoft's NumberFormat difinition for CultureInfo object
147+
* Replica of Microsoft's NumberFormat definition for CultureInfo object
132148
*/
133149
export interface ICultureNumberFormat {
134150
CurrencyDecimalDigits: number;

src/controls/listPicker/IListPicker.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { IDropdownOption } from "office-ui-fabric-react/lib/Dropdown";
2-
import { BaseComponentContext } from '@microsoft/sp-component-base';
31
import { LibsOrderBy } from "../../services/ISPService";
2+
import { BaseComponentContext } from '@microsoft/sp-component-base';
3+
import { IDropdownOption } from "office-ui-fabric-react/lib/Dropdown";
44

55
export interface IListPickerProps {
66
/**
@@ -51,7 +51,7 @@ export interface IListPickerProps {
5151
/**
5252
* Input placeholder text. Displayed until option is selected.
5353
*/
54-
placeholder?: string;
54+
placeholder?: string;
5555
/**
5656
* Callback issued when the selected option changes
5757
*/
@@ -60,6 +60,14 @@ export interface IListPickerProps {
6060
* Absolute Web Url of target site (user requires permissions)
6161
*/
6262
webAbsoluteUrl?: string;
63+
/**
64+
* Content type id which, if present, must be on the list
65+
*/
66+
contentTypeId?: string;
67+
/**
68+
* if present can be used to force the control to refresh the list of lists by toggling its value
69+
*/
70+
refreshToggle?: boolean;
6371
}
6472

6573
export interface IListPickerState {

src/controls/listPicker/ListPicker.tsx

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import * as React from 'react';
2-
import { IDropdownOption, IDropdownProps, Dropdown } from 'office-ui-fabric-react/lib/components/Dropdown';
1+
import { cloneDeep } from '@microsoft/sp-lodash-subset';
2+
import { Dropdown, IDropdownOption, IDropdownProps } from 'office-ui-fabric-react/lib/components/Dropdown';
33
import { Spinner, SpinnerSize } from 'office-ui-fabric-react/lib/components/Spinner';
4-
import { IListPickerProps, IListPickerState } from './IListPicker';
4+
import * as React from 'react';
5+
6+
import * as telemetry from '../../common/telemetry';
57
import { ISPService } from '../../services/ISPService';
68
import { SPServiceFactory } from '../../services/SPServiceFactory';
7-
import * as telemetry from '../../common/telemetry';
8-
9+
import { IListPickerProps, IListPickerState } from './IListPicker';
910
import styles from './ListPicker.module.scss';
10-
import { cloneDeep } from '@microsoft/sp-lodash-subset';
1111

1212
/**
1313
* Empty list value, to be checked for single list selection
@@ -51,7 +51,8 @@ export class ListPicker extends React.Component<IListPickerProps, IListPickerSta
5151
prevProps.baseTemplate !== this.props.baseTemplate ||
5252
prevProps.includeHidden !== this.props.includeHidden ||
5353
prevProps.orderBy !== this.props.orderBy ||
54-
prevProps.webAbsoluteUrl !== this.props.webAbsoluteUrl
54+
prevProps.webAbsoluteUrl !== this.props.webAbsoluteUrl||
55+
prevProps.refreshToggle !== this.props.refreshToggle
5556
) {
5657
this.loadLists();
5758
}
@@ -65,7 +66,8 @@ export class ListPicker extends React.Component<IListPickerProps, IListPickerSta
6566
* Loads the list from SharePoint current web site
6667
*/
6768
private loadLists() {
68-
const { context, baseTemplate, includeHidden, orderBy, multiSelect, filter, webAbsoluteUrl } = this.props;
69+
debugger;
70+
const { context, baseTemplate, includeHidden, orderBy, multiSelect, filter, webAbsoluteUrl, contentTypeId } = this.props;
6971

7072
// Show the loading indicator and disable the dropdown
7173
this.setState({ loading: true });
@@ -75,7 +77,8 @@ export class ListPicker extends React.Component<IListPickerProps, IListPickerSta
7577
baseTemplate: baseTemplate,
7678
includeHidden: includeHidden,
7779
orderBy: orderBy,
78-
filter: filter
80+
filter: filter,
81+
contentTypeId: contentTypeId
7982
}).then((results) => {
8083
let options: IDropdownOption[] = [];
8184

@@ -150,7 +153,7 @@ export class ListPicker extends React.Component<IListPickerProps, IListPickerSta
150153
const dropdownOptions: IDropdownProps = {
151154
className: className,
152155
options: options,
153-
disabled: ( loading || disabled ),
156+
disabled: (loading || disabled),
154157
label: label,
155158
placeHolder: placeholder || placeHolder,
156159
onChanged: this.onChanged
@@ -164,8 +167,8 @@ export class ListPicker extends React.Component<IListPickerProps, IListPickerSta
164167
}
165168

166169
return (
167-
<div className={ styles.listPicker }>
168-
{ loading && <Spinner className={ styles.spinner } size={SpinnerSize.xSmall} /> }
170+
<div className={styles.listPicker}>
171+
{ loading && <Spinner className={styles.spinner} size={SpinnerSize.xSmall} />}
169172
<Dropdown {...dropdownOptions} />
170173
</div>
171174
);

src/controls/sitePicker/ISitePicker.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,10 @@ export interface ISitePickerProps {
4242
* Intial data to load in the 'Selected sites' area (optional)
4343
*/
4444
initialSites?: ISite[];
45+
/**
46+
* used to update the sites currently Selected in the contol
47+
*/
48+
selectedSites?: ISite[];
4549
/**
4650
* Define if you want to allow multi site selection. True by default.
4751
*/

src/controls/sitePicker/SitePicker.tsx

Lines changed: 41 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,17 @@
1-
import * as React from 'react';
2-
import { mergeStyleSets } from 'office-ui-fabric-react/lib/Styling';
3-
import { Spinner, SpinnerSize } from 'office-ui-fabric-react/lib/Spinner';
4-
import { ISite, ISitePickerProps } from './ISitePicker';
5-
import { getAllSites, getHubSites } from '../../services/SPSitesService';
6-
import { IDropdownOption, Dropdown } from 'office-ui-fabric-react/lib/Dropdown';
7-
import { ISelectableOption, SelectableOptionMenuItemType } from 'office-ui-fabric-react/lib/utilities/selectableOption/SelectableOption.types';
8-
import orderBy from 'lodash/orderBy';
1+
import { Async } from '@uifabric/utilities/lib/Async';
92
import findIndex from 'lodash/findIndex';
3+
import orderBy from 'lodash/orderBy';
4+
import { Dropdown, IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown';
105
import { SearchBox } from 'office-ui-fabric-react/lib/SearchBox';
11-
import { toRelativeUrl } from '../../common/utilities/GeneralHelper';
12-
import { Async } from '@uifabric/utilities/lib/Async';
6+
import { Spinner, SpinnerSize } from 'office-ui-fabric-react/lib/Spinner';
7+
import { mergeStyleSets } from 'office-ui-fabric-react/lib/Styling';
8+
import { ISelectableOption, SelectableOptionMenuItemType } from 'office-ui-fabric-react/lib/utilities/selectableOption/SelectableOption.types';
9+
import * as React from 'react';
10+
1311
import * as telemetry from '../../common/telemetry';
12+
import { toRelativeUrl } from '../../common/utilities/GeneralHelper';
13+
import { getAllSites, getHubSites } from '../../services/SPSitesService';
14+
import { ISite, ISitePickerProps } from './ISitePicker';
1415

1516
const styles = mergeStyleSets({
1617
loadingSpinnerContainer: {
@@ -69,11 +70,12 @@ export const SitePicker: React.FunctionComponent<ISitePickerProps> = (props: Rea
6970
placeholder,
7071
searchPlaceholder,
7172
deferredSearchTime,
72-
className
73+
className,
74+
selectedSites
7375
} = props;
7476

7577
const [isLoading, setIsLoading] = React.useState<boolean>();
76-
const [selectedSites, setSelectedSites] = React.useState<ISite[]>();
78+
const [sites, setSites] = React.useState<ISite[]>();
7779
const [allSites, setAllSites] = React.useState<ISite[]>();
7880
const [filteredSites, setFilteredSites] = React.useState<ISite[]>();
7981
const [searchQuery, setSearchQuery] = React.useState<string>();
@@ -92,9 +94,9 @@ export const SitePicker: React.FunctionComponent<ISitePickerProps> = (props: Rea
9294

9395
const onSelectionChange = React.useCallback((e, item: IDropdownOption, index: number) => {
9496
let newSelectedSites: ISite[] = [];
95-
97+
//debugger;
9698
if (multiSelect !== false) {
97-
newSelectedSites = selectedSites ? [...selectedSites] : [];
99+
newSelectedSites = sites ? [...sites] : [];
98100
const existingIndex = findIndex(newSelectedSites, s => s.url === item.key);
99101

100102
if (existingIndex >= 0) {
@@ -116,9 +118,9 @@ export const SitePicker: React.FunctionComponent<ISitePickerProps> = (props: Rea
116118
onChange(newSelectedSites);
117119
}
118120

119-
setSelectedSites(newSelectedSites);
120-
121-
}, [selectedSites, multiSelect, onChange]);
121+
setSites(newSelectedSites);
122+
//console.log(`onselction change set sites to ${newSelectedSites[0].title}`);
123+
}, [sites, multiSelect, onChange]);
122124

123125
const getOptions = React.useCallback((): IDropdownOption[] => {
124126

@@ -140,7 +142,7 @@ export const SitePicker: React.FunctionComponent<ISitePickerProps> = (props: Rea
140142
});
141143
}
142144

143-
const selectedSitesIds: string[] = selectedSites ? selectedSites.map(s => s.url!) : [];
145+
const selectedSitesIds: string[] = sites ? sites.map(s => s.url!) : [];
144146

145147
if (filteredSites) {
146148
filteredSites.forEach(s => {
@@ -154,7 +156,7 @@ export const SitePicker: React.FunctionComponent<ISitePickerProps> = (props: Rea
154156
}
155157

156158
return result;
157-
}, [allowSearch, selectedSites, filteredSites, allSites]);
159+
}, [allowSearch, sites, filteredSites, allSites]);
158160

159161
const onRenderOption = (option?: ISelectableOption, defaultRender?: (props?: ISelectableOption) => JSX.Element | null): JSX.Element | null => {
160162
if (!props) {
@@ -194,17 +196,26 @@ export const SitePicker: React.FunctionComponent<ISitePickerProps> = (props: Rea
194196
telemetry.track('ReactSitePicker');
195197
}, []);
196198

199+
React.useEffect(() => {
200+
//debugger;
201+
setSites(selectedSites);
202+
// console.log(`firt useeffect set sites to ${selectedSites[0].title}`);
203+
if (!allSites) {
204+
setIsLoading(true);
205+
}
206+
}, [selectedSites]);
197207

198208
React.useEffect(() => {
199209
if (!initialSites) {
200210
return;
201211
}
202212

203-
setSelectedSites(sites => {
204-
if (!sites) { // we want to set the state one time only
213+
setSites(osites => {
214+
if (!osites) { // we want to set the state one time only
215+
// console.log(`second useeffect part a set sites to ${initialSites[0].title}`);
205216
return initialSites;
206217
}
207-
218+
// console.log(`second useeffect part b set sites to ${sites[0].title}`);
208219
return sites;
209220
});
210221

@@ -229,21 +240,21 @@ export const SitePicker: React.FunctionComponent<ISitePickerProps> = (props: Rea
229240
promise = getAllSites(context, mode !== 'site', limitToCurrentSiteCollection);
230241
}
231242

232-
promise.then(sites => {
233-
const copy = orderBy(sites, [propOrderBy || 'title'], [isDesc ? 'desc' : 'asc']);
243+
promise.then(newSites => {
244+
const copy = orderBy(newSites, [propOrderBy || 'title'], [isDesc ? 'desc' : 'asc']);
234245
setAllSites(copy);
235246
setIsLoading(false);
236247
});
237248

238249
}, [context, isLoading, mode, limitToCurrentSiteCollection]);
239250

240251
React.useEffect(() => {
241-
setAllSites(sites => {
242-
if (!sites) {
243-
return sites;
252+
setAllSites(s => {
253+
if (!s) {
254+
return s;
244255
}
245256

246-
const copy = orderBy(sites, [propOrderBy || 'title'], [isDesc ? 'desc' : 'asc']);
257+
const copy = orderBy(s, [propOrderBy || 'title'], [isDesc ? 'desc' : 'asc']);
247258
return copy;
248259
});
249260
}, [propOrderBy, isDesc]);
@@ -261,8 +272,8 @@ export const SitePicker: React.FunctionComponent<ISitePickerProps> = (props: Rea
261272
label={label}
262273
placeholder={placeholder}
263274
options={getOptions()}
264-
selectedKey={multiSelect === false && !!selectedSites && !!selectedSites[0] ? selectedSites[0].url : undefined}
265-
selectedKeys={multiSelect !== false && !!selectedSites ? selectedSites.map(s => s.url) : undefined}
275+
selectedKey={multiSelect === false && !!sites && !!sites[0] ? sites[0].url : undefined}
276+
selectedKeys={multiSelect !== false && !!sites ? sites.map(s => s.url) : undefined}
266277
disabled={disabled}
267278
multiSelect={multiSelect !== false}
268279
onRenderOption={onRenderOption}

src/services/ISPService.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@ export interface ILibsOptions {
1313
baseTemplate?: number;
1414
includeHidden?: boolean;
1515
filter?: string;
16+
contentTypeId?: string;
1617
}
1718

1819
export interface ISPService {
20+
1921
/**
2022
* Get the lists from SharePoint
2123
* @param options Options used to order and filter during the API query
2224
*/
2325
getLibs(options?: ILibsOptions): Promise<ISPLists>;
24-
getListItems?(filterText: string, listId: string, internalColumnName: string, field: ISPField, keyInternalColumnName?: string, webUrl?: string) : Promise<any[]>;
26+
getListItems?(filterText: string, listId: string, internalColumnName: string, field: ISPField, keyInternalColumnName?: string, webUrl?: string): Promise<any[]>;
2527
getField: (listId: string, internalColumnName: string, webUrl?: string) => Promise<ISPField | undefined>;
2628
}

0 commit comments

Comments
 (0)