diff --git a/.circleci/config.yml b/.circleci/config.yml index 479a5da4c..7d353014a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,7 +1,7 @@ defaults: &defaults working_directory: ~/sp-dev-fx-controls-react docker: - - image: circleci/node:6.11.5 + - image: circleci/node:8.9.1 version: 2 jobs: diff --git a/CHANGELOG.JSON b/CHANGELOG.JSON index 6376eb432..ee7a17952 100644 --- a/CHANGELOG.JSON +++ b/CHANGELOG.JSON @@ -1,5 +1,36 @@ { "versions": [ + { + "version": "1.10.0", + "changes": { + "new": [ + "`ListItemPicker`: New field control [#165](https://github.com/SharePoint/sp-dev-fx-controls-react/pull/165)" + ], + "enhancements": [ + "Dutch localization added [#100](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/100)", + "German localization added [#101](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/101)", + "French localization added [#102](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/102)", + "`PeoplePicker`: Move defaultSelectedUsers from ComponentWillMount to ComponentDidUpdate Lifecycle [#135](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/135)", + "`PeoplePicker`: Initialize with users from a list item [#138](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/138)", + "`PeoplePicker`: Remove Messagebar error handling to match Office UI Fabric field error styling [#140](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/140)", + "`PeoplePicker`: REST API filter and nometadata header added to reduce payload [#139](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/139)", + "`PeoplePicker`: Allow to set the maximum number of suggestions `suggestionsLimit` [#143](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/143) [#148](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/148)", + "`TaxonomyPicker`: retreiving the terms in the correct custom sort order [#146](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/146)", + "`PeoplePicker`: Documentation format updated to make it easier to check the default values [#159](https://github.com/SharePoint/sp-dev-fx-controls-react/pull/159)" + ], + "fixes": [] + }, + "contributions": [ + "[Marc D Anderson](https://github.com/sympmarc)", + "[Ole Bergtun](https://github.com/trillian74)", + "[João Mendes](https://github.com/joaojmendes)", + "[Markus Möller](https://github.com/mmsharepoint)", + "[Asish Padhy](https://github.com/AsishP)", + "[PooLP](https://github.com/PooLP)", + "[Gautam Sheth](https://github.com/gautamdsheth)", + "[Tse Kit Yam](https://github.com/tsekityam)" + ] + }, { "version": "1.9.0", "changes": { diff --git a/CHANGELOG.md b/CHANGELOG.md index a9c09affe..ca7c8e430 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,28 @@ # Releases +## 1.10.0 + +**New control(s)** + +- `ListItemPicker`: New field control [#165](https://github.com/SharePoint/sp-dev-fx-controls-react/pull/165) + +**Enhancements** + +- Dutch localization added [#100](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/100) +- German localization added [#101](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/101) +- French localization added [#102](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/102) +- `PeoplePicker`: Move defaultSelectedUsers from ComponentWillMount to ComponentDidUpdate Lifecycle [#135](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/135) +- `PeoplePicker`: Initialize with users from a list item [#138](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/138) +- `PeoplePicker`: Remove Messagebar error handling to match Office UI Fabric field error styling [#140](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/140) +- `PeoplePicker`: REST API filter and nometadata header added to reduce payload [#139](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/139) +- `PeoplePicker`: Allow to set the maximum number of suggestions `suggestionsLimit` [#143](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/143) [#148](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/148) +- `TaxonomyPicker`: retreiving the terms in the correct custom sort order [#146](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/146) +- `PeoplePicker`: Documentation format updated to make it easier to check the default values [#159](https://github.com/SharePoint/sp-dev-fx-controls-react/pull/159) + +### Contributors + +Special thanks to our contributors (in alphabetical order): [Marc D Anderson](https://github.com/sympmarc), [Ole Bergtun](https://github.com/trillian74), [João Mendes](https://github.com/joaojmendes), [Markus Möller](https://github.com/mmsharepoint), [Asish Padhy](https://github.com/AsishP), [PooLP](https://github.com/PooLP), [Gautam Sheth](https://github.com/gautamdsheth), [Tse Kit Yam](https://github.com/tsekityam). + ## 1.9.0 **Enhancements** @@ -12,6 +35,10 @@ - `IFrameDialog`: Unnecessary horizontal scroll in IFrame dialog [#132](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/132) - `PeoplePicker`: Suggested People not loading after first selection [#134](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/134) +### Contributors + +Special thanks to our contributors (in alphabetical order): [Gautam Sheth](https://github.com/gautamdsheth), [Alex Terentiev](https://github.com/AJIXuMuK). + ## 1.8.0 **Enhancements** @@ -32,6 +59,10 @@ - `IFrameDialog`: dialog width is not correct in IE11 [#118](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/118) - `PeoplePicker`: fix freezes when typing in search values [#117](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/117) +### Contributors + +Special thanks to our contributors (in alphabetical order): [Thomas Lamb](https://github.com/ThomasLamb), [Joel Rodrigues](https://github.com/joelfmrodrigues), [Mikael Svenson](https://github.com/wobba), [Alex Terentiev](https://github.com/AJIXuMuK). + ## 1.7.0 **Enhancements** @@ -45,6 +76,10 @@ - `FieldNameRenderer` onClick does not suppress default link behavior [#103](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/103) +### Contributors + +Special thanks to our contributors (in alphabetical order): Octavie van Haaften, Asish Padhy, Mikael Svenson, Alex Terentiev. + ## 1.6.0 **Enhancements** @@ -56,6 +91,10 @@ - New telemetry approach which allows you to use Application Insights [#81](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/81) - PeoplePicker property selectedItems not implemented? [#90](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/90) +### Contributors + +Special thanks to our contributor: Octavie van Haaften. + ## 1.5.0 **New control(s)** @@ -72,6 +111,10 @@ - `FieldUserRenderer` uses email prop for `GetPropertiesFor` [#84](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/84) - Fixed issue in single selection mode when all group items were selected in the `ListView` when user clicked on the group header [#86](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/86) +### Contributors + +Special thanks to our contributors (in alphabetical order): Asish Padhy, Alex Terentiev. + ## 1.4.0 **New control(s)** diff --git a/docs/documentation/docs/about/release-notes.md b/docs/documentation/docs/about/release-notes.md index a9c09affe..ca7c8e430 100644 --- a/docs/documentation/docs/about/release-notes.md +++ b/docs/documentation/docs/about/release-notes.md @@ -1,5 +1,28 @@ # Releases +## 1.10.0 + +**New control(s)** + +- `ListItemPicker`: New field control [#165](https://github.com/SharePoint/sp-dev-fx-controls-react/pull/165) + +**Enhancements** + +- Dutch localization added [#100](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/100) +- German localization added [#101](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/101) +- French localization added [#102](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/102) +- `PeoplePicker`: Move defaultSelectedUsers from ComponentWillMount to ComponentDidUpdate Lifecycle [#135](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/135) +- `PeoplePicker`: Initialize with users from a list item [#138](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/138) +- `PeoplePicker`: Remove Messagebar error handling to match Office UI Fabric field error styling [#140](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/140) +- `PeoplePicker`: REST API filter and nometadata header added to reduce payload [#139](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/139) +- `PeoplePicker`: Allow to set the maximum number of suggestions `suggestionsLimit` [#143](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/143) [#148](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/148) +- `TaxonomyPicker`: retreiving the terms in the correct custom sort order [#146](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/146) +- `PeoplePicker`: Documentation format updated to make it easier to check the default values [#159](https://github.com/SharePoint/sp-dev-fx-controls-react/pull/159) + +### Contributors + +Special thanks to our contributors (in alphabetical order): [Marc D Anderson](https://github.com/sympmarc), [Ole Bergtun](https://github.com/trillian74), [João Mendes](https://github.com/joaojmendes), [Markus Möller](https://github.com/mmsharepoint), [Asish Padhy](https://github.com/AsishP), [PooLP](https://github.com/PooLP), [Gautam Sheth](https://github.com/gautamdsheth), [Tse Kit Yam](https://github.com/tsekityam). + ## 1.9.0 **Enhancements** @@ -12,6 +35,10 @@ - `IFrameDialog`: Unnecessary horizontal scroll in IFrame dialog [#132](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/132) - `PeoplePicker`: Suggested People not loading after first selection [#134](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/134) +### Contributors + +Special thanks to our contributors (in alphabetical order): [Gautam Sheth](https://github.com/gautamdsheth), [Alex Terentiev](https://github.com/AJIXuMuK). + ## 1.8.0 **Enhancements** @@ -32,6 +59,10 @@ - `IFrameDialog`: dialog width is not correct in IE11 [#118](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/118) - `PeoplePicker`: fix freezes when typing in search values [#117](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/117) +### Contributors + +Special thanks to our contributors (in alphabetical order): [Thomas Lamb](https://github.com/ThomasLamb), [Joel Rodrigues](https://github.com/joelfmrodrigues), [Mikael Svenson](https://github.com/wobba), [Alex Terentiev](https://github.com/AJIXuMuK). + ## 1.7.0 **Enhancements** @@ -45,6 +76,10 @@ - `FieldNameRenderer` onClick does not suppress default link behavior [#103](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/103) +### Contributors + +Special thanks to our contributors (in alphabetical order): Octavie van Haaften, Asish Padhy, Mikael Svenson, Alex Terentiev. + ## 1.6.0 **Enhancements** @@ -56,6 +91,10 @@ - New telemetry approach which allows you to use Application Insights [#81](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/81) - PeoplePicker property selectedItems not implemented? [#90](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/90) +### Contributors + +Special thanks to our contributor: Octavie van Haaften. + ## 1.5.0 **New control(s)** @@ -72,6 +111,10 @@ - `FieldUserRenderer` uses email prop for `GetPropertiesFor` [#84](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/84) - Fixed issue in single selection mode when all group items were selected in the `ListView` when user clicked on the group header [#86](https://github.com/SharePoint/sp-dev-fx-controls-react/issues/86) +### Contributors + +Special thanks to our contributors (in alphabetical order): Asish Padhy, Alex Terentiev. + ## 1.4.0 **New control(s)** diff --git a/docs/documentation/docs/assets/ListItemPicker-selectedItems.png b/docs/documentation/docs/assets/ListItemPicker-selectedItems.png new file mode 100644 index 000000000..bca220555 Binary files /dev/null and b/docs/documentation/docs/assets/ListItemPicker-selectedItems.png differ diff --git a/docs/documentation/docs/assets/ListItemPicker-selectlist.png b/docs/documentation/docs/assets/ListItemPicker-selectlist.png new file mode 100644 index 000000000..aff7eb624 Binary files /dev/null and b/docs/documentation/docs/assets/ListItemPicker-selectlist.png differ diff --git a/docs/documentation/docs/assets/ListItemPicker-selectlist2.png b/docs/documentation/docs/assets/ListItemPicker-selectlist2.png new file mode 100644 index 000000000..c900bbe7b Binary files /dev/null and b/docs/documentation/docs/assets/ListItemPicker-selectlist2.png differ diff --git a/docs/documentation/docs/assets/placeholder-intro.png b/docs/documentation/docs/assets/placeholder-intro.png new file mode 100644 index 000000000..746f37cfd Binary files /dev/null and b/docs/documentation/docs/assets/placeholder-intro.png differ diff --git a/docs/documentation/docs/controls/ListItemPicker.md b/docs/documentation/docs/controls/ListItemPicker.md new file mode 100644 index 000000000..1aaecca45 --- /dev/null +++ b/docs/documentation/docs/controls/ListItemPicker.md @@ -0,0 +1,59 @@ +# ListItemPicker control + +This control allows you to select one or more items from a list. The item selection is based from a column value. The control will suggest items based on the inserted value. + +Here is an example of the control: + +![ListItemPicker select list items](../assets/ListItemPicker-selectlist.png) + +![ListItemPicker select list items](../assets/ListItemPicker-selectlist2.png) + +![ListItemPicker selected Items](../assets/ListItemPicker-selectedItems.png) + +## How to use this control in your solutions + +- Check that you installed the `@pnp/spfx-controls-react` dependency. Check out the [getting started](../#getting-started) page for more information about installing the dependency. +- Import the control into your component: + +```TypeScript +import { ListItemPicker } from '@pnp/spfx-controls-react/listItemPicker'; +``` +- Use the `ListItemPicker` control in your code as follows: + +```TypeScript + +``` + +- The `onSelectedItem` change event returns the list items selected and can be implemented as follows: + +```TypeScript +private onSelectedItem(data: { key: string; name: string }[]) { + for (const item of data) { + console.log(`Item value: ${item.name}`); + } +} +``` +## Implementation + +The `ListItemPicker` control can be configured with the following properties: + + +| Property | Type | Required | Description | +| ---- | ---- | ---- | ---- | +| columnInternalName | string | yes | InternalName of column to search and get values. | +| context | WebPartContext \| ApplicationCustomizerContext | yes | SPFx web part or extention context | +| listId | string | yes | Guid of the list. | +| itemLimit | number | yes | Number of items which can be selected | +| onSelectItem | (items: any[]) => void | yes | Callback function which returns the selected items. | +| className | string | no | ClassName for the picker. | +| webUrl | string | no | URL of the site. By default it uses the current site URL. | +| defaultSelectedItems | any[] | no | Initial items that have already been selected and should appear in the people picker. | +| suggestionsHeaderText | string | no | The text that should appear at the top of the suggestion box. | +| noResultsFoundText | string | no | The text that should appear when no results are returned. | +| disabled | boolean | no | Specifies if the control is disabled or not. | + +![](https://telemetry.sharepointpnp.com/sp-dev-fx-controls-react/wiki/controls/ListItemPicker) diff --git a/docs/documentation/docs/controls/PeoplePicker.md b/docs/documentation/docs/controls/PeoplePicker.md index 99db205c2..8275b0568 100644 --- a/docs/documentation/docs/controls/PeoplePicker.md +++ b/docs/documentation/docs/controls/PeoplePicker.md @@ -52,26 +52,27 @@ private _getPeoplePickerItems(items: any[]) { The People picker control can be configured with the following properties: -| Property | Type | Required | Description | -| ---- | ---- | ---- | ---- | -| context | WebPartContext | yes | Context of the current web part. | -| titleText | string | yes | Text to be displayed on the control | -| groupName | string | no | group from which users are fetched. Leave it blank if need to filter all users | -| personSelectionLimit | number | no | Defines the limit of people that can be selected in the control| -| isRequired | boolean | no | Set if the control is required or not | -| disabled | boolean | no | Set if the control is disabled or not | -| errorMessage | string | no | Specify the error message to display | -| errorMessageclassName | string | no | applies custom styling to the error message section| -| showtooltip | boolean | no | Defines if need a tooltip or not | -| tooltip | string | no | Specify the tooltip message to display | -| tooltipDirectional | DirectionalHint | no | Direction where the tooltip would be shown | -| selectedItems | function | no | get the selected users in the control | -| peoplePickerWPclassName | string | no | applies custom styling to the people picker element | -| peoplePickerCntrlclassName | string | no | applies custom styling to the people picker control only | -| defaultSelectedUsers | string[] | no | Default selected user emails | -| webAbsoluteUrl | string | no | Specify the site URL on which you want to perform the user query call. Default is the current site URL. | -| showHiddenInUI | boolean | no | Show users which are hidden from the UI. By default these users/groups hidden for the UI will not be shown. | -| principleTypes | PrincipleType[] | no | Define which type of data you want to retrieve: User, SharePoint groups, Security groups. Multiple are possible. | +| Property | Type | Required | Description | Default | +| ---- | ---- | ---- | ---- | ---- | +| context | WebPartContext | yes | Context of the current web part. | | +| titleText | string | yes | Text to be displayed on the control | | +| groupName | string | no | group from which users are fetched. Leave it blank if need to filter all users | _none_ | +| personSelectionLimit | number | no | Defines the limit of people that can be selected in the control | | +| isRequired | boolean | no | Set if the control is required or not | false | +| disabled | boolean | no | Set if the control is disabled or not | false | +| errorMessage | string | no | Specify the error message to display | | +| errorMessageClassName | string | no | applies custom styling to the error message section | | +| showtooltip | boolean | no | Defines if need a tooltip or not | false | +| tooltip | string | no | Specify the tooltip message to display | | +| tooltipDirectional | DirectionalHint | no | Direction where the tooltip would be shown | | +| selectedItems | function | no | get the selected users in the control | | +| peoplePickerWPclassName | string | no | applies custom styling to the people picker element | | +| peoplePickerCntrlclassName | string | no | applies custom styling to the people picker control only | | +| defaultSelectedUsers | string[] | no | Default selected user emails | | +| webAbsoluteUrl | string | no | Specify the site URL on which you want to perform the user query call. | Current site URL | +| showHiddenInUI | boolean | no | Show users which are hidden from the UI. By default these users/groups hidden for the UI will not be shown. | false | +| principleTypes | PrincipleType[] | no | Define which type of data you want to retrieve: User, SharePoint groups, Security groups. Multiple are possible. | | +| suggestionsLimit | number | no | Maximum number of suggestions to show in the full suggestion list. | 5 | Enum `PrincipalType` diff --git a/docs/documentation/docs/index.md b/docs/documentation/docs/index.md index 61d49af16..bbe4240f2 100644 --- a/docs/documentation/docs/index.md +++ b/docs/documentation/docs/index.md @@ -2,6 +2,8 @@ This repository provides developers with a set of reusable React controls that can be used in SharePoint Framework (SPFx) solutions. The project provides controls for building web parts and extensions. +![Placeholder example](./assets/placeholder-intro.png) + !!! attention The controls project has a minimal dependency on SharePoint Framework version `1.3.0`. Be aware that the controls might not work in solutions your building for on-premises. As for on-premises solutions version `1.1.0` is currently used. diff --git a/package-lock.json b/package-lock.json index 82f913b9f..7037c03c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@pnp/spfx-controls-react", - "version": "1.9.0", + "version": "1.10.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -1352,6 +1352,12 @@ } } }, + "@sindresorhus/is": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.7.0.tgz", + "integrity": "sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==", + "dev": true + }, "@types/adal": { "version": "1.0.27", "resolved": "https://registry.npmjs.org/@types/adal/-/adal-1.0.27.tgz", @@ -3012,6 +3018,34 @@ } } }, + "buffer-alloc": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz", + "integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==", + "dev": true, + "requires": { + "buffer-alloc-unsafe": "^1.1.0", + "buffer-fill": "^1.0.0" + } + }, + "buffer-alloc-unsafe": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz", + "integrity": "sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==", + "dev": true + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", + "dev": true + }, + "buffer-fill": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz", + "integrity": "sha1-+PeLdniYiO858gXNY39o5wISKyw=", + "dev": true + }, "buffer-xor": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", @@ -3065,6 +3099,60 @@ "rimraf": "^2.4.0" } }, + "cacheable-request": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-2.1.4.tgz", + "integrity": "sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=", + "dev": true, + "requires": { + "clone-response": "1.0.2", + "get-stream": "3.0.0", + "http-cache-semantics": "3.8.1", + "keyv": "3.0.0", + "lowercase-keys": "1.0.0", + "normalize-url": "2.0.1", + "responselike": "1.0.2" + }, + "dependencies": { + "normalize-url": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-2.0.1.tgz", + "integrity": "sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==", + "dev": true, + "requires": { + "prepend-http": "^2.0.0", + "query-string": "^5.0.1", + "sort-keys": "^2.0.0" + } + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "query-string": { + "version": "5.1.1", + "resolved": "http://registry.npmjs.org/query-string/-/query-string-5.1.1.tgz", + "integrity": "sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==", + "dev": true, + "requires": { + "decode-uri-component": "^0.2.0", + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, + "sort-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-2.0.0.tgz", + "integrity": "sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=", + "dev": true, + "requires": { + "is-plain-obj": "^1.0.0" + } + } + } + }, "callsite": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", @@ -3127,6 +3215,18 @@ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, + "caw": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/caw/-/caw-2.0.1.tgz", + "integrity": "sha512-Cg8/ZSBEa8ZVY9HspcGUYaK63d/bN7rqS3CYCzEGUxuYv6UlmcjzDUz2fCFFHyTvUW5Pk0I+3hkA3iXlIj6guA==", + "dev": true, + "requires": { + "get-proxy": "^2.0.0", + "isurl": "^1.0.0-alpha5", + "tunnel-agent": "^0.6.0", + "url-to-options": "^1.0.1" + } + }, "center-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", @@ -3409,6 +3509,15 @@ "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", "dev": true }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, "clone-stats": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", @@ -3825,6 +3934,16 @@ } } }, + "config-chain": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", + "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "dev": true, + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, "configstore": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/configstore/-/configstore-2.1.0.tgz", @@ -4471,6 +4590,139 @@ } } }, + "decompress": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/decompress/-/decompress-4.2.0.tgz", + "integrity": "sha1-eu3YVCflqS2s/lVnSnxQXpbQH50=", + "dev": true, + "requires": { + "decompress-tar": "^4.0.0", + "decompress-tarbz2": "^4.0.0", + "decompress-targz": "^4.0.0", + "decompress-unzip": "^4.0.1", + "graceful-fs": "^4.1.10", + "make-dir": "^1.0.0", + "pify": "^2.3.0", + "strip-dirs": "^2.0.0" + } + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "decompress-tar": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tar/-/decompress-tar-4.1.1.tgz", + "integrity": "sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==", + "dev": true, + "requires": { + "file-type": "^5.2.0", + "is-stream": "^1.1.0", + "tar-stream": "^1.5.2" + }, + "dependencies": { + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", + "dev": true + } + } + }, + "decompress-tarbz2": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-tarbz2/-/decompress-tarbz2-4.1.1.tgz", + "integrity": "sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==", + "dev": true, + "requires": { + "decompress-tar": "^4.1.0", + "file-type": "^6.1.0", + "is-stream": "^1.1.0", + "seek-bzip": "^1.0.5", + "unbzip2-stream": "^1.0.9" + }, + "dependencies": { + "file-type": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-6.2.0.tgz", + "integrity": "sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==", + "dev": true + } + } + }, + "decompress-targz": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/decompress-targz/-/decompress-targz-4.1.1.tgz", + "integrity": "sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==", + "dev": true, + "requires": { + "decompress-tar": "^4.1.1", + "file-type": "^5.2.0", + "is-stream": "^1.1.0" + }, + "dependencies": { + "file-type": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-5.2.0.tgz", + "integrity": "sha1-LdvqfHP/42No365J3DOMBYwritY=", + "dev": true + } + } + }, + "decompress-unzip": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/decompress-unzip/-/decompress-unzip-4.0.1.tgz", + "integrity": "sha1-3qrM39FK6vhVePczroIQ+bSEj2k=", + "dev": true, + "requires": { + "file-type": "^3.8.0", + "get-stream": "^2.2.0", + "pify": "^2.3.0", + "yauzl": "^2.4.2" + }, + "dependencies": { + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", + "dev": true, + "requires": { + "pend": "~1.2.0" + } + }, + "file-type": { + "version": "3.9.0", + "resolved": "http://registry.npmjs.org/file-type/-/file-type-3.9.0.tgz", + "integrity": "sha1-JXoHg4TR24CHvESdEH1SpSZyuek=", + "dev": true + }, + "get-stream": { + "version": "2.3.1", + "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-2.3.1.tgz", + "integrity": "sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + } + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", + "dev": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + } + } + }, "deep-eql": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz", @@ -4696,6 +4948,79 @@ "is-obj": "^1.0.0" } }, + "download": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/download/-/download-7.0.0.tgz", + "integrity": "sha512-0Fe/CAjKycx12IG9We9gYlLP03BEcWTpttg7P5mwfOiQTg584kpuHqP7F61RkUJM+mfEdEU9TJonm0PJp5rQLw==", + "dev": true, + "requires": { + "caw": "^2.0.1", + "content-disposition": "^0.5.2", + "decompress": "^4.2.0", + "ext-name": "^5.0.0", + "file-type": "^7.7.1", + "filenamify": "^2.0.0", + "get-stream": "^3.0.0", + "got": "^8.3.1", + "make-dir": "^1.2.0", + "p-event": "^1.3.0", + "pify": "^3.0.0" + }, + "dependencies": { + "got": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/got/-/got-8.3.2.tgz", + "integrity": "sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.7.0", + "cacheable-request": "^2.1.1", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "into-stream": "^3.1.0", + "is-retry-allowed": "^1.1.0", + "isurl": "^1.0.0-alpha5", + "lowercase-keys": "^1.0.0", + "mimic-response": "^1.0.0", + "p-cancelable": "^0.4.0", + "p-timeout": "^2.0.1", + "pify": "^3.0.0", + "safe-buffer": "^5.1.1", + "timed-out": "^4.0.1", + "url-parse-lax": "^3.0.0", + "url-to-options": "^1.0.1" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } + } + } + }, "duplexer": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", @@ -4711,6 +5036,12 @@ "readable-stream": "~1.1.9" } }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, "duplexify": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.5.3.tgz", @@ -5609,6 +5940,25 @@ } } }, + "ext-list": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ext-list/-/ext-list-2.2.2.tgz", + "integrity": "sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==", + "dev": true, + "requires": { + "mime-db": "^1.28.0" + } + }, + "ext-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ext-name/-/ext-name-5.0.0.tgz", + "integrity": "sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==", + "dev": true, + "requires": { + "ext-list": "^2.0.0", + "sort-keys-length": "^1.0.0" + } + }, "extend": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", @@ -5758,12 +6108,35 @@ "loader-utils": "~0.2.5" } }, + "file-type": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-7.7.1.tgz", + "integrity": "sha512-bTrKkzzZI6wH+NXhyD3SOXtb2zXTw2SbwI2RxUlRcXVsnN7jNL5hJzVQLYv7FOQhxFkK4XWdAflEaWFpaLLWpQ==", + "dev": true + }, "filename-regex": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", "dev": true }, + "filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha1-q/c9+rc10EVECr/qLZHzieu/oik=", + "dev": true + }, + "filenamify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-2.1.0.tgz", + "integrity": "sha512-ICw7NTT6RsDp2rnYKVd8Fu4cr6ITzGy3+u4vUujPkabyaz+03F24NWEX7fs5fp+kBonlaqPH8fAO2NM+SXt/JA==", + "dev": true, + "requires": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.0", + "trim-repeated": "^1.0.0" + } + }, "fill-range": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", @@ -5944,6 +6317,60 @@ "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", "dev": true }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true + }, "fs-extra": { "version": "0.26.7", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.26.7.tgz", @@ -6583,6 +7010,15 @@ "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=", "dev": true }, + "get-proxy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/get-proxy/-/get-proxy-2.1.0.tgz", + "integrity": "sha512-zmZIaQTWnNQb4R4fJUEp/FC51eZsc6EkErspy3xtIYStaq8EB/hDIWipxsal+E8rz0qD7f2sL/NA9Xee4RInJw==", + "dev": true, + "requires": { + "npm-conf": "^1.1.0" + } + }, "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", @@ -8442,12 +8878,27 @@ "sparkles": "^1.0.0" } }, + "has-symbol-support-x": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz", + "integrity": "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==", + "dev": true + }, "has-symbols": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", "dev": true }, + "has-to-string-tag-x": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz", + "integrity": "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==", + "dev": true, + "requires": { + "has-symbol-support-x": "^1.4.1" + } + }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", @@ -8691,6 +9142,12 @@ } } }, + "http-cache-semantics": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz", + "integrity": "sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==", + "dev": true + }, "http-errors": { "version": "1.6.2", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", @@ -8844,6 +9301,16 @@ "integrity": "sha1-ftGxQQxqDg94z5XTuEQMY/eLhhQ=", "dev": true }, + "into-stream": { + "version": "3.1.0", + "resolved": "http://registry.npmjs.org/into-stream/-/into-stream-3.1.0.tgz", + "integrity": "sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=", + "dev": true, + "requires": { + "from2": "^2.1.1", + "p-is-promise": "^1.1.0" + } + }, "invert-kv": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", @@ -9021,6 +9488,12 @@ "xtend": "^4.0.0" } }, + "is-natural-number": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-natural-number/-/is-natural-number-4.0.1.tgz", + "integrity": "sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=", + "dev": true + }, "is-npm": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", @@ -9053,6 +9526,12 @@ "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", "dev": true }, + "is-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-object/-/is-object-1.0.1.tgz", + "integrity": "sha1-iVJojF7C/9awPsyF52ngKQMINHA=", + "dev": true + }, "is-odd": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-odd/-/is-odd-1.0.0.tgz", @@ -9332,6 +9811,16 @@ "textextensions": "~1.0.0" } }, + "isurl": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz", + "integrity": "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==", + "dev": true, + "requires": { + "has-to-string-tag-x": "^1.2.0", + "is-object": "^1.0.1" + } + }, "jju": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/jju/-/jju-1.3.0.tgz", @@ -9380,6 +9869,12 @@ "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", "dev": true }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, "json-loader": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz", @@ -9670,6 +10165,15 @@ "integrity": "sha1-edk9LTM2PW/dKXCzNdkUGtWR15s=", "dev": true }, + "keyv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.0.0.tgz", + "integrity": "sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, "kind-of": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", @@ -10429,6 +10933,23 @@ "integrity": "sha1-WQTcU3w57G2+/q6QIycTX6hRHxI=", "dev": true }, + "make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, "make-iterator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.0.tgz", @@ -10719,6 +11240,12 @@ "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=", "dev": true }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, "minimalistic-assert": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz", @@ -11414,6 +11941,24 @@ "sort-keys": "^1.0.0" } }, + "npm-conf": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", + "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", + "dev": true, + "requires": { + "config-chain": "^1.1.11", + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, "npm-run-path": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", @@ -11828,12 +12373,44 @@ "os-tmpdir": "^1.0.0" } }, + "p-cancelable": { + "version": "0.4.1", + "resolved": "http://registry.npmjs.org/p-cancelable/-/p-cancelable-0.4.1.tgz", + "integrity": "sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==", + "dev": true + }, + "p-event": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-event/-/p-event-1.3.0.tgz", + "integrity": "sha1-jmtPT2XHK8W2/ii3XtqHT5akoIU=", + "dev": true, + "requires": { + "p-timeout": "^1.1.1" + }, + "dependencies": { + "p-timeout": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz", + "integrity": "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y=", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + } + } + }, "p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", "dev": true }, + "p-is-promise": { + "version": "1.1.0", + "resolved": "http://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", + "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=", + "dev": true + }, "p-limit": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", @@ -11852,6 +12429,15 @@ "p-limit": "^1.1.0" } }, + "p-timeout": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/p-timeout/-/p-timeout-2.0.1.tgz", + "integrity": "sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==", + "dev": true, + "requires": { + "p-finally": "^1.0.0" + } + }, "p-try": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", @@ -12855,6 +13441,12 @@ "object-assign": "^4.1.1" } }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=", + "dev": true + }, "proxy-addr": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.5.tgz", @@ -13544,6 +14136,15 @@ "on-headers": "~1.0.1" } }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, "right-align": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", @@ -13685,6 +14286,26 @@ } } }, + "seek-bzip": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/seek-bzip/-/seek-bzip-1.0.5.tgz", + "integrity": "sha1-z+kXyz0nS8/6x5J1ivUxc+sfq9w=", + "dev": true, + "requires": { + "commander": "~2.8.1" + }, + "dependencies": { + "commander": { + "version": "2.8.1", + "resolved": "http://registry.npmjs.org/commander/-/commander-2.8.1.tgz", + "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=", + "dev": true, + "requires": { + "graceful-readlink": ">= 1.0.0" + } + } + } + }, "semver": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", @@ -13990,6 +14611,12 @@ "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=", "dev": true }, + "slugify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.3.1.tgz", + "integrity": "sha512-6BwyhjF5tG5P8s+0DPNyJmBSBePG6iMyhjvIW5zGdA3tFik9PtK+yNkZgTeiroCRGZYgkHftFA62tGVK1EI9Kw==", + "dev": true + }, "snapdragon": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.1.tgz", @@ -14250,6 +14877,69 @@ } } }, + "sonarqube-scanner": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/sonarqube-scanner/-/sonarqube-scanner-2.1.2.tgz", + "integrity": "sha512-4Sf01R7zOnR3YTofaQI5HH6UTz46l0kUov7cJvWmhD9Hi+U16komI/e61GjOyC2JrVrFiWqFsO/o15ceHbKd/Q==", + "dev": true, + "requires": { + "download": "7.0.0", + "extend": "3.0.1", + "fancy-log": "^1.1.0", + "lodash.get": "^4.4.2", + "lodash.uniq": "^4.5.0", + "mkdirp": "0.5.1", + "progress": "^2.0.0", + "read-pkg": "2.0.0", + "slugify": "1.3.1" + }, + "dependencies": { + "load-json-file": { + "version": "2.0.0", + "resolved": "http://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "strip-bom": "^3.0.0" + } + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "^2.0.0" + } + }, + "progress": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz", + "integrity": "sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg==", + "dev": true + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "^2.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^2.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + } + } + }, "sort-keys": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", @@ -14259,6 +14949,15 @@ "is-plain-obj": "^1.0.0" } }, + "sort-keys-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sort-keys-length/-/sort-keys-length-1.0.1.tgz", + "integrity": "sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=", + "dev": true, + "requires": { + "sort-keys": "^1.0.0" + } + }, "source-list-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz", @@ -14723,6 +15422,15 @@ } } }, + "strip-dirs": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strip-dirs/-/strip-dirs-2.1.0.tgz", + "integrity": "sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==", + "dev": true, + "requires": { + "is-natural-number": "^4.0.1" + } + }, "strip-eof": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", @@ -14744,6 +15452,15 @@ "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", "dev": true }, + "strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, "sudo": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sudo/-/sudo-1.0.3.tgz", @@ -14820,6 +15537,59 @@ "inherits": "2" } }, + "tar-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz", + "integrity": "sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==", + "dev": true, + "requires": { + "bl": "^1.0.0", + "buffer-alloc": "^1.2.0", + "end-of-stream": "^1.0.0", + "fs-constants": "^1.0.0", + "readable-stream": "^2.3.0", + "to-buffer": "^1.1.1", + "xtend": "^4.0.0" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "http://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, "ternary-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/ternary-stream/-/ternary-stream-2.0.1.tgz", @@ -15066,6 +15836,12 @@ "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", "dev": true }, + "to-buffer": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz", + "integrity": "sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==", + "dev": true + }, "to-object-path": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", @@ -15196,6 +15972,15 @@ "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", "dev": true }, + "trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.2" + } + }, "true-case-path": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.2.tgz", @@ -15424,6 +16209,41 @@ "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po=", "dev": true }, + "unbzip2-stream": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.1.tgz", + "integrity": "sha512-fIZnvdjblYs7Cru/xC6tCPVhz7JkYcVQQkePwMLyQELzYTds2Xn8QefPVnvdVhhZqubxNA1cASXEH5wcK0Bucw==", + "dev": true, + "requires": { + "buffer": "^3.0.1", + "through": "^2.3.6" + }, + "dependencies": { + "base64-js": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", + "integrity": "sha1-EQHpVE9KdrG8OybUUsqW16NeeXg=", + "dev": true + }, + "buffer": { + "version": "3.6.0", + "resolved": "http://registry.npmjs.org/buffer/-/buffer-3.6.0.tgz", + "integrity": "sha1-pyyTb3e5a/UvX357RnGAYoVR3vs=", + "dev": true, + "requires": { + "base64-js": "0.0.8", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, "unc-path-regex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", @@ -15639,6 +16459,12 @@ "prepend-http": "^1.0.1" } }, + "url-to-options": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz", + "integrity": "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=", + "dev": true + }, "urlgrey": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/urlgrey/-/urlgrey-0.4.4.tgz", diff --git a/package.json b/package.json index 9ce266927..cffff5e38 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@pnp/spfx-controls-react", "description": "Reusable React controls for SharePoint Framework solutions", - "version": "1.9.0", + "version": "1.10.0", "engines": { "node": ">=0.10.0" }, @@ -52,7 +52,7 @@ "react": "15.4.2", "react-addons-test-utils": "15.6.0", "react-dom": "15.4.2", - "sonarqube-scanner": "2.1.1" + "sonarqube-scanner": "2.1.2" }, "repository": { "type": "git", diff --git a/scripts/create-changelog.js b/scripts/create-changelog.js index 9054b11d6..c3a03fd2e 100644 --- a/scripts/create-changelog.js +++ b/scripts/create-changelog.js @@ -29,6 +29,14 @@ if (changelog.versions && changelog.versions.length > 0) { } } } + + // Add the contributions to the MD file + if (entry.contributions && entry.contributions.length > 0) { + markdown.push(`### Contributors`); + markdown.push(``); + markdown.push(`Special thanks to our contributor${entry.contributions.length > 1 ? "s (in alphabetical order)" : "" }: ${entry.contributions.join(', ')}.`); + markdown.push(``); + } } if (markdown.length > 2) { diff --git a/src/ListItemPicker.ts b/src/ListItemPicker.ts new file mode 100644 index 000000000..be6838119 --- /dev/null +++ b/src/ListItemPicker.ts @@ -0,0 +1 @@ +export * from './controls/listItemPicker'; diff --git a/src/common/telemetry/version.ts b/src/common/telemetry/version.ts index 78aadc4f3..ab0e836b7 100644 --- a/src/common/telemetry/version.ts +++ b/src/common/telemetry/version.ts @@ -1 +1 @@ -export const version: string = "1.9.0"; \ No newline at end of file +export const version: string = "1.10.0"; \ No newline at end of file diff --git a/src/controls/listItemPicker/IListItemPickerProps.ts b/src/controls/listItemPicker/IListItemPickerProps.ts new file mode 100644 index 000000000..96e2499ab --- /dev/null +++ b/src/controls/listItemPicker/IListItemPickerProps.ts @@ -0,0 +1,18 @@ +import { WebPartContext } from "@microsoft/sp-webpart-base"; +import { ApplicationCustomizerContext } from "@microsoft/sp-application-base"; + +export interface IListItemPickerProps { + columnInternalName: string; + context: WebPartContext | ApplicationCustomizerContext; + listId: string; + itemLimit: number; + + className?: string; + webUrl?: string; + defaultSelectedItems?: any[]; + disabled?: boolean; + suggestionsHeaderText?:string; + noResultsFoundText?:string; + + onSelectedItem: (item:any) => void; +} diff --git a/src/controls/listItemPicker/IListItemPickerState.ts b/src/controls/listItemPicker/IListItemPickerState.ts new file mode 100644 index 000000000..9c6a3de79 --- /dev/null +++ b/src/controls/listItemPicker/IListItemPickerState.ts @@ -0,0 +1,6 @@ +export interface IListItemPickerState { + noresultsFoundText: string; + showError: boolean; + errorMessage: string; + suggestionsHeaderText:string; +} diff --git a/src/controls/listItemPicker/ListItemPicker.tsx b/src/controls/listItemPicker/ListItemPicker.tsx new file mode 100644 index 000000000..449720a39 --- /dev/null +++ b/src/controls/listItemPicker/ListItemPicker.tsx @@ -0,0 +1,137 @@ +import * as strings from 'ControlStrings'; +import * as React from "react"; +import SPservice from "../../services/SPService"; +import { escape } from "@microsoft/sp-lodash-subset"; +import { TagPicker } from "office-ui-fabric-react/lib/components/pickers/TagPicker/TagPicker"; +import { Label } from "office-ui-fabric-react/lib/Label"; +import { IListItemPickerProps, IListItemPickerState } from "."; +import * as telemetry from '../../common/telemetry'; + + +export class ListItemPicker extends React.Component { + private _spservice: SPservice; + private selectedItems: any[]; + + constructor(props: IListItemPickerProps) { + super(props); + + telemetry.track('ListItemPicker', {}); + + // States + this.state = { + noresultsFoundText: !this.props.noResultsFoundText ? strings.genericNoResultsFoundText : this.props.noResultsFoundText, + showError: false, + errorMessage: "", + suggestionsHeaderText: !this.props.suggestionsHeaderText ? strings.ListItemPickerSelectValue : this.props.suggestionsHeaderText + }; + + // Get SPService Factory + this._spservice = new SPservice(this.props.context); + + this.selectedItems = []; + } + + public componentDidUpdate(prevProps: IListItemPickerProps, prevState: IListItemPickerState): void { + if (this.props.listId !== prevProps.listId) { + this.selectedItems = []; + } + } + + /** + * Render the field + */ + public render(): React.ReactElement { + const { className, disabled, itemLimit } = this.props; + + return ( +
+ { return item.name; }} + getTextFromItem={this.getTextFromItem} + pickerSuggestionsProps={{ + suggestionsHeaderText: this.state.suggestionsHeaderText, + noResultsFoundText: this.state.noresultsFoundText + }} + defaultSelectedItems={this.props.defaultSelectedItems || []} + onChange={this.onItemChanged} + className={className} + itemLimit={itemLimit} + disabled={disabled} /> + + +
+ ); + } + + /** + * Get text from Item + */ + private getTextFromItem(item: any): string { + return item.name; + } + + /** + * On Selected Item + */ + private onItemChanged = (selectedItems: { key: string; name: string }[]): void => { + this.selectedItems = selectedItems; + this.props.onSelectedItem(selectedItems); + } + + /** + * Filter Change + */ + private onFilterChanged = async (filterText: string, tagList: { key: string; name: string }[]) => { + let resolvedSugestions: { key: string; name: string }[] = await this.loadListItems(filterText); + + // Filter out the already retrieved items, so that they cannot be selected again + if (this.selectedItems && this.selectedItems.length > 0) { + let filteredSuggestions = []; + for (const suggestion of resolvedSugestions) { + const exists = this.selectedItems.filter(sItem => sItem.key === suggestion.key); + if (!exists || exists.length === 0) { + filteredSuggestions.push(suggestion); + } + } + resolvedSugestions = filteredSuggestions; + } + + if (resolvedSugestions) { + this.setState({ + errorMessage: "", + showError: false + }); + + return resolvedSugestions; + } else { + return []; + } + } + + /** + * Function to load List Items + */ + private loadListItems = async (filterText: string): Promise<{ key: string; name: string }[]> => { + let { listId, columnInternalName, webUrl } = this.props; + let arrayItems: { key: string; name: string }[] = []; + + try { + let listItems = await this._spservice.getListItems(filterText, listId, columnInternalName, webUrl); + // Check if the list had items + if (listItems.length > 0) { + for (const item of listItems) { + arrayItems.push({ key: item.Id, name: item[columnInternalName] }); + } + } + return arrayItems; + } catch (error) { + console.log(`Error get Items`, error); + this.setState({ + showError: true, + errorMessage: error.message, + noresultsFoundText: error.message + }); + return null; + } + } +} diff --git a/src/controls/listItemPicker/index.ts b/src/controls/listItemPicker/index.ts new file mode 100644 index 000000000..1f118bfde --- /dev/null +++ b/src/controls/listItemPicker/index.ts @@ -0,0 +1,4 @@ +// A file is required to be in the root of the /src directory by the TypeScript compiler +export * from './IListItemPickerProps'; +export * from './IListItemPickerState'; +export * from './ListItemPicker'; diff --git a/src/controls/peoplepicker/IPeoplePicker.ts b/src/controls/peoplepicker/IPeoplePicker.ts index 63351d76f..16282355b 100644 --- a/src/controls/peoplepicker/IPeoplePicker.ts +++ b/src/controls/peoplepicker/IPeoplePicker.ts @@ -28,6 +28,10 @@ export interface IPeoplePickerProps { * Name of SharePoint Group */ groupName?: string; + /** + * Maximum number of suggestions to show in the full suggestion list. (default: 5) + */ + suggestionsLimit?: number; /** * Selection Limit of Control */ @@ -67,7 +71,7 @@ export interface IPeoplePickerProps { /** * Class Name for the Error Section */ - errorMessageclassName?: string; + errorMessageClassName?: string; /** * Default Selected User Emails */ diff --git a/src/controls/peoplepicker/PeoplePickerComponent.module.scss b/src/controls/peoplepicker/PeoplePickerComponent.module.scss index 1b3e8cef4..3c035896b 100644 --- a/src/controls/peoplepicker/PeoplePickerComponent.module.scss +++ b/src/controls/peoplepicker/PeoplePickerComponent.module.scss @@ -1,3 +1,18 @@ .defaultClass { - color : black; + color : black; +} + +.errorMessage { + font-size: 12px; + font-weight: 400; + color: #a80000; + margin: 0; + padding-top: 5px; + display: flex; + align-items: center; +} + +.errorIcon { + font-size: 14px; + margin-right: 5px; } diff --git a/src/controls/peoplepicker/PeoplePickerComponent.tsx b/src/controls/peoplepicker/PeoplePickerComponent.tsx index 38b7d29d5..94669b78a 100644 --- a/src/controls/peoplepicker/PeoplePickerComponent.tsx +++ b/src/controls/peoplepicker/PeoplePickerComponent.tsx @@ -16,12 +16,8 @@ import { IPersonaWithMenu } from "office-ui-fabric-react/lib/components/pickers/ import { IPersonaProps } from "office-ui-fabric-react/lib/components/Persona/Persona.types"; import { MessageBarType } from "office-ui-fabric-react/lib/components/MessageBar"; import { ValidationState } from 'office-ui-fabric-react/lib/components/pickers/BasePicker.types'; - -const suggestionProps: IBasePickerSuggestionsProps = { - suggestionsHeaderText: 'Suggested People', - noResultsFoundText: 'No results found', - loadingText: 'Loading' -}; +import { Icon } from "office-ui-fabric-react/lib/components/Icon"; +import { isEqual } from "@microsoft/sp-lodash-subset"; /** * PeoplePicker component @@ -44,8 +40,8 @@ export class PeoplePicker extends React.Component = this.state.allPersons.length !==0 ? this.state.allPersons : new Array(); + + // Set Default selected persons + let defaultUsers : any = []; + let defaultPeopleList: IPersonaProps[] = []; + if (this.props.defaultSelectedUsers) { + defaultUsers = this.getDefaultUsers(userValuesArray, this.props.defaultSelectedUsers); + for (const persona of defaultUsers) { + let selectedPeople: IPersonaProps = {}; + assign(selectedPeople, persona); + defaultPeopleList.push(selectedPeople); + } } + + this.setState({ + selectedPersons : defaultPeopleList.length !== 0 ? defaultPeopleList : [], + showmessageerror: this.props.isRequired && defaultPeopleList.length === 0 + }); + } } /** @@ -69,7 +93,7 @@ export class PeoplePicker extends React.Component { - var stringVal = ""; + var stringVal: string = ""; + if (this.props.groupName) { stringVal = `/_api/web/sitegroups/GetByName('${this.props.groupName}')/users`; } else { stringVal = "/_api/web/siteusers"; } + // filter for principal Type + var filterVal: string = ""; + if (this.props.principleTypes) { + filterVal = `?$filter=${this.props.principleTypes.map(principalType => `(PrincipalType eq ${principalType})`).join(" or ")}`; + } + + // filter for showHiddenInUI + if (this.props.showHiddenInUI) { + filterVal = filterVal ? `${filterVal} and (IsHiddenInUI eq ${this.props.showHiddenInUI})` : `?$filter=IsHiddenInUI eq ${this.props.showHiddenInUI}`; + } + const webAbsoluteUrl = this.props.webAbsoluteUrl || this.props.context.pageContext.web.absoluteUrl; // Create the rest API - const restApi = `${webAbsoluteUrl}${stringVal}`; + const restApi = `${webAbsoluteUrl}${stringVal}${filterVal}`; try { // Call the API endpoint - const items: IUsers = await this.props.context.spHttpClient.get(restApi, SPHttpClient.configurations.v1).then(resp => resp.json()); - - // Check if items were retrieved - if (items && items.value && items.value.length > 0) { - - let userValuesArray: Array = new Array(); - - // Loop over all the retrieved items - for (let i = 0; i < items.value.length; i++) { - const item = items.value[i]; - if (!item.IsHiddenInUI || (this.props.showHiddenInUI && item.IsHiddenInUI)) { - // Check if the the type must be returned - if (!this.props.principleTypes || this.props.principleTypes.indexOf(item.PrincipalType) !== -1) { - userValuesArray.push({ - id: item.Id.toString(), - imageUrl: this.generateUserPhotoLink(item.Email), - imageInitials: "", - text: item.Title, // name - secondaryText: item.Email, // email - tertiaryText: "", // status - optionalText: "" // anything - }); + const data = await this.props.context.spHttpClient.get(restApi, SPHttpClient.configurations.v1, { + headers: { + 'Accept': 'application/json;odata.metadata=none' + } + }); + + if (data.ok) { + const items: IUsers = await data.json(); + + // Check if items were retrieved + if (items && items.value && items.value.length > 0) { + + let userValuesArray: Array = new Array(); + + // Loop over all the retrieved items + for (let i = 0; i < items.value.length; i++) { + const item = items.value[i]; + if (!item.IsHiddenInUI || (this.props.showHiddenInUI && item.IsHiddenInUI)) { + // Check if the the type must be returned + if (!this.props.principleTypes || this.props.principleTypes.indexOf(item.PrincipalType) !== -1) { + userValuesArray.push({ + id: item.Id.toString(), + imageUrl: this.generateUserPhotoLink(item.Email), + imageInitials: "", + text: item.Title, // name + secondaryText: item.Email, // email + tertiaryText: "", // status + optionalText: "" // anything + }); + } } } - } - // Set Default selected persons - let defaultUsers : any = []; - let defaultPeopleList: IPersonaProps[] = []; - if (this.props.defaultSelectedUsers) { - defaultUsers = this.getDefaultUsers(userValuesArray, this.props.defaultSelectedUsers); - for (const persona of defaultUsers) { - let selectedPeople: IPersonaProps = {}; - assign(selectedPeople, persona); - defaultPeopleList.push(selectedPeople); + let personaList: IPersonaProps[] = []; + for (const persona of userValuesArray) { + let personaWithMenu: IPersonaProps = {}; + assign(personaWithMenu, persona); + personaList.push(personaWithMenu); } - } - let personaList: IPersonaProps[] = []; - for (const persona of userValuesArray) { - let personaWithMenu: IPersonaProps = {}; - assign(personaWithMenu, persona); - personaList.push(personaWithMenu); + // Update the current state + this.setState({ + allPersons : userValuesArray, + peoplePersonaMenu : personaList, + mostRecentlyUsedPersons : personaList.slice(0,5) + }); } - - // Update the current state - this.setState({ - allPersons : userValuesArray, - selectedPersons : defaultPeopleList.length != 0 ? defaultPeopleList : [], - peoplePersonaMenu : personaList, - mostRecentlyUsedPersons : personaList.slice(0,5), - showmessageerror: this.props.isRequired && this.state.selectedPersons.length === 0 - }); } } catch (e) { console.error("Error occured while fetching the users and setting selected users."); @@ -275,10 +305,10 @@ export class PeoplePicker extends React.Component - this._doesTextStartWith(item.text as string, filterText) - || this._doesTextContains(item.text as string, filterText) - || this._doesTextStartWith(item.secondaryText as string, filterText) - || this._doesTextContains(item.secondaryText as string, filterText)); + this._doesTextStartWith(item.text as string, filterText) + || this._doesTextContains(item.text as string, filterText) + || this._doesTextStartWith(item.secondaryText as string, filterText) + || this._doesTextContains(item.secondaryText as string, filterText)); } @@ -302,12 +332,12 @@ export class PeoplePicker extends React.Component 0; } @@ -332,23 +362,23 @@ export class PeoplePicker extends React.Component { + const suggestionProps: IBasePickerSuggestionsProps = { + suggestionsHeaderText: strings.peoplePickerSuggestionsHeaderText, + noResultsFoundText: strings.genericNoResultsFoundText, + loadingText: strings.peoplePickerLoadingText, + resultsMaximumNumber: this.props.suggestionsLimit ? this.props.suggestionsLimit : 5 + }; + + const peoplepicker = (
peoplePersonaMenu.text} - className={`'ms-PeoplePicker' ${this.props.peoplePickerCntrlclassName ? this.props.peoplePickerCntrlclassName : ''}`} - key={'normal'} - onValidateInput={this._validateInputPeople} - removeButtonAriaLabel={'Remove'} - inputProps={{ - 'aria-label': 'People Picker' - }} - selectedItems={this.state.selectedPersons} - itemLimit={this.props.personSelectionLimit || 1} - disabled={this.props.disabled} - onChange={this._onPersonItemsChange} /> + onResolveSuggestions={this._onPersonFilterChanged} + onEmptyInputFocus={this._returnMostRecentlyUsedPerson} + getTextFromItem={(peoplePersonaMenu: IPersonaProps) => peoplePersonaMenu.text} + className={`'ms-PeoplePicker' ${this.props.peoplePickerCntrlclassName ? this.props.peoplePickerCntrlclassName : ''}`} + key={'normal'} + onValidateInput={this._validateInputPeople} + removeButtonAriaLabel={'Remove'} + inputProps={{ + 'aria-label': 'People Picker' + }} + selectedItems={this.state.selectedPersons} + itemLimit={this.props.personSelectionLimit || 1} + disabled={this.props.disabled} + onChange={this._onPersonItemsChange} />
); return (
- { - this.props.showtooltip ? ( - - {peoplepicker} - - ) : ( -
- {peoplepicker} -
- ) - } + { + this.props.showtooltip ? ( + + {peoplepicker} + + ) : ( +
+ {peoplepicker} +
+ ) + } { (this.props.isRequired && this.state.showmessageerror) && ( - - {this.props.errorMessage ? this.props.errorMessage : strings.peoplePickerComponentErrorMessage} - +

+ + {this.props.errorMessage ? this.props.errorMessage : strings.peoplePickerComponentErrorMessage} +

) }
diff --git a/src/index.ts b/src/index.ts index abfcf3225..f1fe003fa 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,7 @@ export * from './SiteBreadcrumb'; export * from './TaxonomyPicker'; export * from './WebPartTitle'; export * from './ListPicker'; +export * from './ListItemPicker'; export * from './IFrameDialog'; export * from './Common'; diff --git a/src/loc/de-de.ts b/src/loc/de-de.ts new file mode 100644 index 000000000..350f17dbd --- /dev/null +++ b/src/loc/de-de.ts @@ -0,0 +1,59 @@ +declare var define: any; + +define([], () => { + return { + 'SiteBreadcrumbLabel': 'Website Brotkrume', + + 'ListViewGroupEmptyLabel': 'Leer', + + 'WebPartTitlePlaceholder': 'Webpart Titel', + 'WebPartTitleLabel': 'Titel hinzufügen', + + "DateTime": { + "L_RelativeDateTime_AFewSecondsFuture": "In wenigen Sekunden", + "L_RelativeDateTime_AFewSeconds": "Vor wenigen Sekunden", + "L_RelativeDateTime_AboutAMinuteFuture": "In ungefähr einer Minute", + "L_RelativeDateTime_AboutAMinute": "Vor ungefähr einer Minute", + "L_RelativeDateTime_XMinutesFuture": "In {0} Minute||In {0} Minuten", + "L_RelativeDateTime_XMinutes": "Vor {0} Minute||Vor {0} Minuten", + "L_RelativeDateTime_XMinutesFutureIntervals": "1||2-", + "L_RelativeDateTime_XMinutesIntervals": "1||2-", + "L_RelativeDateTime_AboutAnHourFuture": "In ungefähr einer Stunde", + "L_RelativeDateTime_AboutAnHour": "Vor ungefähr einer Stunde", + "L_RelativeDateTime_Tomorrow": "Morgen", + "L_RelativeDateTime_Yesterday": "Gestern", + "L_RelativeDateTime_TomorrowAndTime": "Morgen um {0}", + "L_RelativeDateTime_YesterdayAndTime": "Gestern um {0}", + "L_RelativeDateTime_XHoursFuture": "In {0} Stunde||In {0} Stunden", + "L_RelativeDateTime_XHours": "Vor {0} Stunde||Vor {0} Stunden", + "L_RelativeDateTime_XHoursFutureIntervals": "1||2-", + "L_RelativeDateTime_XHoursIntervals": "1||2-", + "L_RelativeDateTime_DayAndTime": "{0} at {1}", + "L_RelativeDateTime_XDaysFuture": "{0} Tag ab jetzt||{0} Tage ab jetzt", + "L_RelativeDateTime_XDays": "Vor {0} Tag||Vor {0} Tagen", + "L_RelativeDateTime_XDaysFutureIntervals": "1||2-", + "L_RelativeDateTime_XDaysIntervals": "1||2-", + "L_RelativeDateTime_Today": "Heute" + }, + "SendEmailTo": "Email senden an {0}", + "StartChatWith": "Chat starten mit {0}", + "Contact": "Kontakt", + "UpdateProfile": "Aktualisiere Dein Profil", + + "TaxonomyPickerNoTerms": "Ausdruckssatz enthält keine Ausdrücke", + "TaxonomyPickerExpandTitle": "Ausdruckssatz erweitern", + "TaxonomyPickerMenuTermSet": "Ausdruckssatz Menü", + "TaxonomyPickerInLabel": "in", + "TaxonomyPickerTermSetLabel": "Ausdruckssatz", + + peoplePickerComponentTooltipMessage: "People Picker", + peoplePickerComponentErrorMessage: "Benutzerauswahl ist ein Pflichtfeld", + peoplePickerComponentTitleText: "Benutzer auswählen", + peoplePickerSuggestionsHeaderText: 'Vorgeschlagene Benutzer', + peoplePickerLoadingText: 'Laden', + + ListItemPickerSelectValue: 'Wähle Wert', + + genericNoResultsFoundText: 'Kein Ergebnis gefunden' + }; +}); diff --git a/src/loc/en-us.ts b/src/loc/en-us.ts index 84399efbe..4948bbc2a 100644 --- a/src/loc/en-us.ts +++ b/src/loc/en-us.ts @@ -47,7 +47,13 @@ define([], () => { "TaxonomyPickerTermSetLabel": "Term Set", peoplePickerComponentTooltipMessage: "People Picker", - peoplePickerComponentErrorMessage: "People picker is mandatory", + peoplePickerComponentErrorMessage: "Required Field", peoplePickerComponentTitleText: "Pick the user(s)", + peoplePickerSuggestionsHeaderText: 'Suggested People', + peoplePickerLoadingText: 'Loading', + + ListItemPickerSelectValue: 'Select value', + + genericNoResultsFoundText: 'No results found' }; }); diff --git a/src/loc/fr-fr.ts b/src/loc/fr-fr.ts new file mode 100644 index 000000000..75359af7a --- /dev/null +++ b/src/loc/fr-fr.ts @@ -0,0 +1,59 @@ +declare var define: any; + +define([], () => { + return { + 'SiteBreadcrumbLabel': 'Fil d\'Ariane', + + 'ListViewGroupEmptyLabel': 'Vide', + + 'WebPartTitlePlaceholder': 'Titre du WebPart', + 'WebPartTitleLabel': 'Ajouter un titre', + + "DateTime": { + "L_RelativeDateTime_AFewSecondsFuture": "Dans quelques secondes", + "L_RelativeDateTime_AFewSeconds": "Il ya quelques secondes", + "L_RelativeDateTime_AboutAMinuteFuture": "Dans environ une minute", + "L_RelativeDateTime_AboutAMinute": "Il y a environ une minute", + "L_RelativeDateTime_XMinutesFuture": "Dans {0} minute||Dans {0} minutes", + "L_RelativeDateTime_XMinutes": "Il y a {0} minute||Il y a {0} minutes", + "L_RelativeDateTime_XMinutesFutureIntervals": "1||2-", + "L_RelativeDateTime_XMinutesIntervals": "1||2-", + "L_RelativeDateTime_AboutAnHourFuture": "Dans environ une heure", + "L_RelativeDateTime_AboutAnHour": "Il y a à peu près une heure", + "L_RelativeDateTime_Tomorrow": "Demain", + "L_RelativeDateTime_Yesterday": "Hier", + "L_RelativeDateTime_TomorrowAndTime": "Demain à {0}", + "L_RelativeDateTime_YesterdayAndTime": "Hier à {0}", + "L_RelativeDateTime_XHoursFuture": "Dans {0} heure||Dans {0} heures", + "L_RelativeDateTime_XHours": "Il y a {0} heure||Il y a {0} heures", + "L_RelativeDateTime_XHoursFutureIntervals": "1||2-", + "L_RelativeDateTime_XHoursIntervals": "1||2-", + "L_RelativeDateTime_DayAndTime": "{0} à {1}", + "L_RelativeDateTime_XDaysFuture": "{0} jours à partir de maintenant || {0} jours à partir de maintenant", + "L_RelativeDateTime_XDays": "Il y a {0} jour||Il y a {0} jours", + "L_RelativeDateTime_XDaysFutureIntervals": "1||2-", + "L_RelativeDateTime_XDaysIntervals": "1||2-", + "L_RelativeDateTime_Today": "Aujourd'hui" + }, + "SendEmailTo": "Envoyer un email à {0}", + "StartChatWith": "Démarrer une discussion avec {0}", + "Contact": "Contact", + "UpdateProfile": "Mettre à jour votre profil", + + "TaxonomyPickerNoTerms": "L'ensemble de termes ne contient aucun terme", + "TaxonomyPickerExpandTitle": "Développer cet ensemble de termes", + "TaxonomyPickerMenuTermSet": "Menu pour l'ensemble de termes", + "TaxonomyPickerInLabel": "dans", + "TaxonomyPickerTermSetLabel": "Ensemble de termes", + + peoplePickerComponentTooltipMessage: "Sélecteur de personnes", + peoplePickerComponentErrorMessage: "Le sélecteur de personnes est obligatoire", + peoplePickerComponentTitleText: "Choisissez l'utilisateur(s)", + peoplePickerSuggestionsHeaderText: 'Personnes suggérées', + peoplePickerLoadingText: 'Chargement', + + ListItemPickerSelectValue: 'Sélectionnez une valeur', + + genericNoResultsFoundText: 'Aucun résultat trouvé' + }; +}); diff --git a/src/loc/mystrings.d.ts b/src/loc/mystrings.d.ts index 6d3bce692..2b58ffa1b 100644 --- a/src/loc/mystrings.d.ts +++ b/src/loc/mystrings.d.ts @@ -2,6 +2,11 @@ declare interface IControlStrings { peoplePickerComponentTooltipMessage: string; peoplePickerComponentErrorMessage: string; peoplePickerComponentTitleText: string; + peoplePickerSuggestionsHeaderText: string; + genericNoResultsFoundText: string; + peoplePickerLoadingText: string; + + SiteBreadcrumbLabel: string; ListViewGroupEmptyLabel: string; WebPartTitlePlaceholder: string; @@ -18,6 +23,8 @@ declare interface IControlStrings { TaxonomyPickerMenuTermSet: string; TaxonomyPickerInLabel: string; TaxonomyPickerTermSetLabel: string; + + ListItemPickerSelectValue: string; } declare module 'ControlStrings' { diff --git a/src/loc/nl-nl.ts b/src/loc/nl-nl.ts new file mode 100644 index 000000000..541730aab --- /dev/null +++ b/src/loc/nl-nl.ts @@ -0,0 +1,59 @@ +declare var define: any; + +define([], () => { + return { + 'SiteBreadcrumbLabel': 'Website broodkruimelpad', + + 'ListViewGroupEmptyLabel': 'Leeg', + + 'WebPartTitlePlaceholder': 'Webonderdeel titel', + 'WebPartTitleLabel': 'Titel ingeven', + + "DateTime": { + "L_RelativeDateTime_AFewSecondsFuture": "Over een paar seconden", + "L_RelativeDateTime_AFewSeconds": "Een paar seconden geleden", + "L_RelativeDateTime_AboutAMinuteFuture": "Over ongeveer een minuut", + "L_RelativeDateTime_AboutAMinute": "Ongeveer een minuut geleden", + "L_RelativeDateTime_XMinutesFuture": "In {0} minuut||In {0} minuten", + "L_RelativeDateTime_XMinutes": "{0} minuut geleden||{0} minuten geleden", + "L_RelativeDateTime_XMinutesFutureIntervals": "1||2-", + "L_RelativeDateTime_XMinutesIntervals": "1||2-", + "L_RelativeDateTime_AboutAnHourFuture": "In ongeveer een uur", + "L_RelativeDateTime_AboutAnHour": "Ongeveer een uur geleden", + "L_RelativeDateTime_Tomorrow": "Morgen", + "L_RelativeDateTime_Yesterday": "Gisteren", + "L_RelativeDateTime_TomorrowAndTime": "Morgen om {0}", + "L_RelativeDateTime_YesterdayAndTime": "Gisteren om {0}", + "L_RelativeDateTime_XHoursFuture": "In {0} uur||In {0} uur", + "L_RelativeDateTime_XHours": "{0} uur geleden||{0} uur geleden", + "L_RelativeDateTime_XHoursFutureIntervals": "1||2-", + "L_RelativeDateTime_XHoursIntervals": "1||2-", + "L_RelativeDateTime_DayAndTime": "{0} om {1}", + "L_RelativeDateTime_XDaysFuture": "{0} dag vanaf nu||{0} dagen vanaf nu", + "L_RelativeDateTime_XDays": "{0} dag geleden||{0} dagen geleden", + "L_RelativeDateTime_XDaysFutureIntervals": "1||2-", + "L_RelativeDateTime_XDaysIntervals": "1||2-", + "L_RelativeDateTime_Today": "Vandaag" + }, + "SendEmailTo": "Stuur een mail naar {0}", + "StartChatWith": "Start een gesprek met {0}", + "Contact": "Contacteer", + "UpdateProfile": "Profiel aanpassen", + + "TaxonomyPickerNoTerms": "Termen set heeft geen termen beschikbaar", + "TaxonomyPickerExpandTitle": "Vouw de termen set uit", + "TaxonomyPickerMenuTermSet": "Menu van de termen set", + "TaxonomyPickerInLabel": "in", + "TaxonomyPickerTermSetLabel": "Termen set", + + peoplePickerComponentTooltipMessage: "Personen kiezen", + peoplePickerComponentErrorMessage: "Verplicht veld", + peoplePickerComponentTitleText: "Kies personen", + peoplePickerSuggestionsHeaderText: 'Voorgestelde personen', + peoplePickerLoadingText: 'Laden', + + ListItemPickerSelectValue: 'Selecteer veld', + + genericNoResultsFoundText: 'Geen resultaten gevonden' + }; +}); diff --git a/src/services/ISPService.ts b/src/services/ISPService.ts index c62fa8a8e..d808ccd8f 100644 --- a/src/services/ISPService.ts +++ b/src/services/ISPService.ts @@ -4,6 +4,7 @@ export enum LibsOrderBy { Id = 1, Title } + /** * Options used to sort and filter */ @@ -12,10 +13,12 @@ export interface ILibsOptions { baseTemplate?: number; includeHidden?: boolean; } + export interface ISPService { /** * Get the lists from SharePoint * @param options Options used to order and filter during the API query */ getLibs(options?: ILibsOptions): Promise; -} \ No newline at end of file + getListItems?(filterText: string, listId: string, internalColumnName: string, webUrl?: string) : Promise; +} diff --git a/src/services/ISPTermStorePickerService.ts b/src/services/ISPTermStorePickerService.ts index e2c36afc6..130737919 100644 --- a/src/services/ISPTermStorePickerService.ts +++ b/src/services/ISPTermStorePickerService.ts @@ -32,6 +32,7 @@ export interface ITermSet { _ObjectType_: string; // SP.Taxonomy.TermSet _ObjectIdentity_: string; Id: string; + CustomSortOrder?:string; Name: string; Description: string; Names: ITermSetNames; @@ -71,6 +72,7 @@ export interface ITerm { IsRoot: boolean; PathOfTerm: string; TermSet: ITermSetMinimal; + CustomSortOrderIndex?: number; PathDepth?: number; ParentId?: string; } diff --git a/src/services/SPService.ts b/src/services/SPService.ts index a68bbd60a..615f02093 100644 --- a/src/services/SPService.ts +++ b/src/services/SPService.ts @@ -1,7 +1,7 @@ import { ISPService, ILibsOptions, LibsOrderBy } from "./ISPService"; import { ISPLists } from "../common/SPEntities"; import { WebPartContext } from "@microsoft/sp-webpart-base"; -import { ApplicationCustomizerContext } from '@microsoft/sp-application-base'; +import { ApplicationCustomizerContext } from "@microsoft/sp-application-base"; import { SPHttpClient, SPHttpClientResponse } from "@microsoft/sp-http"; export default class SPService implements ISPService { @@ -12,7 +12,7 @@ export default class SPService implements ISPService { * Get lists or libraries * @param options */ - public getLibs(options?: ILibsOptions): Promise { + public async getLibs(options?: ILibsOptions): Promise { let filtered: boolean; let queryUrl: string = `${this._context.pageContext.web.absoluteUrl}/_api/web/lists?$select=Title,id,BaseTemplate`; @@ -30,7 +30,34 @@ export default class SPService implements ISPService { filtered = true; } - return this._context.spHttpClient.get(queryUrl, SPHttpClient.configurations.v1) - .then(response => response.json()) as Promise; + const data = await this._context.spHttpClient.get(queryUrl, SPHttpClient.configurations.v1); + if (data.ok) { + return await data.json() as Promise; + } else { + return null; + } + } + + /** + * Get List Items + */ + public async getListItems(filterText: string, listId: string, internalColumnName: string, webUrl?: string): Promise { + let returnItems: any[]; + + try { + const webAbsoluteUrl = !webUrl ? this._context.pageContext.web.absoluteUrl : webUrl; + const apiUrl = `${webAbsoluteUrl}/_api/web/lists('${listId}')/items?$select=Id,${internalColumnName}&$filter=startswith(${internalColumnName},'${filterText}')`; + const data = await this._context.spHttpClient.get(apiUrl, SPHttpClient.configurations.v1); + if (data.ok) { + const results = await data.json(); + if (results && results.value && results.value.length > 0) { + return results.value; + } + } + + return []; + } catch (error) { + return Promise.reject(error); + } } } diff --git a/src/services/SPTermStorePickerService.ts b/src/services/SPTermStorePickerService.ts index 02a9601f7..3b6604590 100644 --- a/src/services/SPTermStorePickerService.ts +++ b/src/services/SPTermStorePickerService.ts @@ -115,7 +115,7 @@ export default class SPTermStorePickerService { public async getAllTerms(termset: string): Promise { if (Environment.type === EnvironmentType.Local) { // If the running environment is local, load the data from the mock - return this.getAllMockTerms(); + return this.getAllMockTerms(); } else { let termsetId: string = termset; // Check if the provided term set property is a GUID or string @@ -158,12 +158,12 @@ export default class SPTermStorePickerService { let terms = termStoreResultTerms[0]._Child_Items_; // Clean the term ID and specify the path depth terms = terms.map(term => { + term.CustomSortOrderIndex = (termStoreResultTermSet.CustomSortOrder) ? termStoreResultTermSet.CustomSortOrder.split(":").indexOf(this.cleanGuid(term.Id)) : -1; term.Id = this.cleanGuid(term.Id); term['PathDepth'] = term.PathOfTerm.split(';').length; - term.TermSet = { Id : this.cleanGuid(termStoreResultTermSet.Id), Name : termStoreResultTermSet.Name}; - if (term["Parent"]) - { - term.ParentId = this.cleanGuid(term["Parent"].Id); + term.TermSet = { Id: this.cleanGuid(termStoreResultTermSet.Id), Name: termStoreResultTermSet.Name }; + if (term["Parent"]) { + term.ParentId = this.cleanGuid(term["Parent"].Id); } return term; }); @@ -274,7 +274,7 @@ export default class SPTermStorePickerService { terms.forEach(term => { if (term.Name.toLowerCase().indexOf(searchText.toLowerCase()) !== -1) { returnTerms.push({ - key:this.cleanGuid(term.Id), + key: this.cleanGuid(term.Id), name: term.Name, path: term.PathOfTerm, termSet: this.cleanGuid(term.TermSet.Id), @@ -302,13 +302,24 @@ export default class SPTermStorePickerService { * @param b term 2 */ private _sortTerms(a: ITerm, b: ITerm) { - if (a.PathOfTerm < b.PathOfTerm) { - return -1; - } - if (a.PathOfTerm > b.PathOfTerm) { - return 1; + if(a.CustomSortOrderIndex === -1){ + if (a.PathOfTerm < b.PathOfTerm) { + return -1; + } + if (a.PathOfTerm > b.PathOfTerm) { + return 1; + } + return 0; + }else{ + if (a.CustomSortOrderIndex < b.CustomSortOrderIndex) { + return -1; + } + if (a.CustomSortOrderIndex > b.CustomSortOrderIndex) { + return 1; + } + return 0; } - return 0; + } /** diff --git a/src/webparts/controlsTest/components/ControlsTest.tsx b/src/webparts/controlsTest/components/ControlsTest.tsx index 7ec830e7c..18ff386f0 100644 --- a/src/webparts/controlsTest/components/ControlsTest.tsx +++ b/src/webparts/controlsTest/components/ControlsTest.tsx @@ -18,6 +18,8 @@ import { Environment, EnvironmentType } from '@microsoft/sp-core-library'; import { SecurityTrimmedControl, PermissionLevel } from '../../../SecurityTrimmedControl'; import { SPPermission } from '@microsoft/sp-page-context'; import { PeoplePicker, PrincipalType } from '../../../PeoplePicker'; +import { getItemClassNames } from 'office-ui-fabric-react/lib/components/ContextualMenu/ContextualMenu.classNames'; +import { ListItemPicker } from "../../../ListItemPicker"; /** * Component that can be used to test out the React controls from this project @@ -30,7 +32,9 @@ export default class ControlsTest extends React.Component { return resp.json(); }) + // .then(items => { + // let emails : string[] = items.value ? items.value.map((item, key)=> { return item.Author.EMail}) : []; + // console.log(emails); + // this.setState({ + // authorEmails: emails + // }); + // }); } /** @@ -76,6 +92,20 @@ export default class ControlsTest extends React.Component { console.log("Lists:", lists); + this.setState({ + selectedList: typeof lists === "string" ? lists : lists.pop() + }); } /** @@ -107,13 +140,22 @@ export default class ControlsTest extends React.Component -
TaxonomyPicker tester: +
Field picker list data tester: + +
+ +
Services tester: + + + + + principleTypes={[PrincipalType.User]} + suggestionsLimit={2} />