diff --git a/packages/sp/src/fields.ts b/packages/sp/src/fields.ts index 054a8a7cc..a9fa8d9fa 100644 --- a/packages/sp/src/fields.ts +++ b/packages/sp/src/fields.ts @@ -6,6 +6,7 @@ import { FieldTypes, CalendarType, UrlFieldFormatType, + FieldUserSelectionMode, } from "./types"; /** @@ -66,12 +67,12 @@ export class Fields extends SharePointQueryableCollection { const postBody: string = JSON.stringify({ "parameters": - Util.extend({ - "__metadata": - { - "type": "SP.XmlSchemaFieldCreationInformation", - }, - }, info), + Util.extend({ + "__metadata": + { + "type": "SP.XmlSchemaFieldCreationInformation", + }, + }, info), }); return this.clone(Fields, "createfieldasxml").postCore<{ Id: string }>({ body: postBody }).then((data) => { @@ -299,6 +300,58 @@ export class Fields extends SharePointQueryableCollection { return this.add(title, "SP.FieldUrl", Util.extend(props, properties)); } + + /** Adds a user field to the colleciton + * + * @param title The new field's title + * @param selectionMode The selection mode of the field + * @param selectionGroup Value that specifies the identifier of the SharePoint group whose members can be selected as values of the field + * @param properties + */ + public addUser(title: string, + selectionMode: FieldUserSelectionMode, + properties?: TypedHash): Promise { + + const props = { + FieldTypeKind: 20, + SelectionMode: selectionMode, + }; + + return this.add(title, "SP.FieldUser", Util.extend(props, properties)); + } + + /** + * Adds a SP.FieldLookup to the collection + * + * @param title The new field's title + * @param lookupListId The guid id of the list where the source of the lookup is found + * @param lookupFieldName The internal name of the field in the source list + * @param properties Set of additional properties to set on the new field + */ + public addLookup( + title: string, + lookupListId: string, + lookupFieldName: string, + properties?: TypedHash, + ): Promise { + + const postBody: string = JSON.stringify({ + parameters: Util.extend({ + FieldTypeKind: 7, + LookupFieldName: lookupFieldName, + LookupListId: lookupListId, + Title: title, + "__metadata": { "type": "SP.FieldCreationInformation" }, + }, properties), + }); + + return this.clone(Fields, "addfield").postCore<{ Id: string }>({ body: postBody }).then((data) => { + return { + data: data, + field: this.getById(data.Id), + }; + }); + } } /** diff --git a/packages/sp/src/items.ts b/packages/sp/src/items.ts index 9ac427f44..8c87fb645 100644 --- a/packages/sp/src/items.ts +++ b/packages/sp/src/items.ts @@ -8,6 +8,7 @@ import { ListItemFormUpdateValue } from "./types"; import { ODataParserBase } from "@pnp/odata"; import { AttachmentFiles } from "./attachmentfiles"; import { List } from "./lists"; +import { Logger, LogLevel } from "@pnp/logging"; /** * Describes a collection of Item objects @@ -63,7 +64,58 @@ export class Items extends SharePointQueryableCollection { return this.get(new PagedItemCollectionParser()); } - // +/** + * Gets all the items in a list, regardless of count. Does not support batching or caching + * + * @param requestSize Number of items to return in each request (Default: 2000) + */ + public getAll(requestSize = 2000): Promise { + + Logger.write("Calling items.getAll should be done sparingly. Ensure this is the correct choice. If you are unsure, it is not.", LogLevel.Warning); + + // this will be used for the actual query + // and we set no metadata here to try and reduce traffic + const items = new Items(this, "").top(requestSize).configure({ + headers: { + "Accept": "application/json;odata=nometadata", + }, + }); + + // let's copy over the odata query params that can be applied + // $top - allow setting the page size this way (override what we did above) + // $select - allow picking the return fields (good behavior) + // $filter - allow setting a filter, though this may fail due for large lists + this.query.getKeys() + .filter(k => /^\$select$|^\$filter$|^\$top$/.test(k.toLowerCase())) + .reduce((i, k) => { + i.query.add(k, this.query.get(k)); + return i; + }, items); + + // give back the promise + return new Promise((resolve, reject) => { + + // this will eventually hold the items we return + const itemsCollector: any[] = []; + + // action that will gather up our results recursively + const gatherer = (last: PagedItemCollection) => { + + // collect that set of results + [].push.apply(itemsCollector, last.results); + + // if we have more, repeat - otherwise resolve with the collected items + if (last.hasNext) { + last.getNext().then(gatherer).catch(reject); + } else { + resolve(itemsCollector); + } + }; + + // start the cycle + items.getPaged().then(gatherer).catch(reject); + }); + } /** * Adds a new item to the collection diff --git a/packages/sp/src/types.ts b/packages/sp/src/types.ts index d6d3be86b..08d6159d0 100644 --- a/packages/sp/src/types.ts +++ b/packages/sp/src/types.ts @@ -1426,3 +1426,8 @@ export interface MenuNodeCollection { StartingNodeTitle: string; Version: Date; } + +export enum FieldUserSelectionMode { + PeopleAndGroups = 1, + PeopleOnly = 0, +}