Fixed readme, linting, typos, sample manifest, removed upgrade files, updated devcontainer
|
@ -1,15 +1,14 @@
|
||||||
// For more information on how to run this SPFx project in a VS Code Remote Container, please visit https://aka.ms/spfx-devcontainer
|
|
||||||
{
|
{
|
||||||
"name": "SPFx 1.0.0",
|
"name": "SPFx 1.17.1",
|
||||||
"image": "docker.io/m365pnp/spfx:ga",
|
"image": "docker.io/m365pnp/spfx:1.17.1",
|
||||||
// Set *default* container specific settings.json values on container create.
|
"customizations": {
|
||||||
"settings": {},
|
"vscode": {
|
||||||
// Add the IDs of extensions you want installed when the container is created.
|
|
||||||
"extensions": [
|
"extensions": [
|
||||||
"editorconfig.editorconfig",
|
"editorconfig.editorconfig",
|
||||||
"dbaeumer.vscode-eslint"
|
"dbaeumer.vscode-eslint"
|
||||||
],
|
]
|
||||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
}
|
||||||
|
},
|
||||||
"forwardPorts": [
|
"forwardPorts": [
|
||||||
4321,
|
4321,
|
||||||
35729,
|
35729,
|
||||||
|
|
|
@ -7,9 +7,11 @@ echo
|
||||||
echo -e "\e[1;94mGenerating dev certificate\e[0m"
|
echo -e "\e[1;94mGenerating dev certificate\e[0m"
|
||||||
gulp trust-dev-cert
|
gulp trust-dev-cert
|
||||||
|
|
||||||
|
# Convert the generated PEM certificate to a CER certificate
|
||||||
|
openssl x509 -inform PEM -in ~/.rushstack/rushstack-serve.pem -outform DER -out ./spfx-dev-cert.cer
|
||||||
|
|
||||||
cp ~/.gcb-serve-data/gcb-serve.cer ./spfx-dev-cert.cer
|
# Copy the PEM ecrtificate for non-Windows hosts
|
||||||
cp ~/.gcb-serve-data/gcb-serve.cer ./spfx-dev-cert.pem
|
cp ~/.rushstack/rushstack-serve.pem ./spfx-dev-cert.pem
|
||||||
|
|
||||||
## add *.cer to .gitignore to prevent certificates from being saved in repo
|
## add *.cer to .gitignore to prevent certificates from being saved in repo
|
||||||
if ! grep -Fxq '*.cer' ./.gitignore
|
if ! grep -Fxq '*.cer' ./.gitignore
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
v16.20.0
|
|
@ -1,9 +1,9 @@
|
||||||
# Property Bag Navigation Webparts
|
# Property Bag Navigation Web parts
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
A set of webparts that lets you set property bag settings on site collections and enable navigation using those properties.
|
|
||||||
|
|
||||||
[picture of the web part in action]
|
A set of web parts that lets you set property bag settings on site collections and enable navigation using those properties.
|
||||||
|
![PropertyBagEditorDisplay](./assets/PropertyBagEditorDisplay.PNG)
|
||||||
|
|
||||||
## Compatibility
|
## Compatibility
|
||||||
|
|
||||||
|
@ -26,8 +26,6 @@ A set of webparts that lets you set property bag settings on site collections an
|
||||||
* [SharePoint Framework](https://blogs.office.com/2017/02/23/sharepoint-framework-reaches-general-availability-build-and-deploy-engaging-web-parts-today/)
|
* [SharePoint Framework](https://blogs.office.com/2017/02/23/sharepoint-framework-reaches-general-availability-build-and-deploy-engaging-web-parts-today/)
|
||||||
* [Microsoft 365 tenant](https://learn.microsoft.com/sharepoint/dev/spfx/set-up-your-development-environment)
|
* [Microsoft 365 tenant](https://learn.microsoft.com/sharepoint/dev/spfx/set-up-your-development-environment)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Prerequisites
|
## Prerequisites
|
||||||
|
|
||||||
> pnp-js-core
|
> pnp-js-core
|
||||||
|
@ -43,52 +41,53 @@ Version|Date|Comments
|
||||||
1.0|march 19, 2017|Initial release
|
1.0|march 19, 2017|Initial release
|
||||||
2.0|Feb 21, 2024|Upgraded to SPFX 1.17.1
|
2.0|Feb 21, 2024|Upgraded to SPFX 1.17.1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
## Minimal Path to Awesome
|
## Minimal Path to Awesome
|
||||||
|
|
||||||
- Clone this repository
|
* Clone this repository
|
||||||
- This project uses the JSOM to interact with the property bag. Therefore in config/config.js you need to change the paths
|
* This project uses the JSOM to interact with the property bag. Therefore in config/config.js you need to change the paths
|
||||||
on the externals sp-init,microsoft-ajax,sp-runtime, and sharepoint to point to your tenant.
|
on the externals `sp-init`,`microsoft-ajax`,`sp-runtime`, and SharePoint to point to your tenant.
|
||||||
- in the command line run:
|
* in the command line run:
|
||||||
- `npm install`
|
* `npm install`
|
||||||
- `gulp serve`
|
* `gulp serve`
|
||||||
|
|
||||||
> This sample can also be opened with [VS Code Remote Development](https://code.visualstudio.com/docs/remote/remote-overview). Visit https://aka.ms/spfx-devcontainer for further instructions.
|
> This sample can also be opened with [VS Code Remote Development](https://code.visualstudio.com/docs/remote/remote-overview). Visit <https://aka.ms/spfx-devcontainer> for further instructions.
|
||||||
|
|
||||||
> Note that using the JSOM to updates the propertybag of a site is not supported on 'NoScript' sites. You can enable scripts on all sites using the admnin center or via powershell:
|
> Note that using the JSOM to updates the property bag of a site is not supported on 'NoScript' sites. You can enable scripts on all sites using the admin center or via PowerShell:
|
||||||
Set-PnPTenantSite -Identity {SiteUrl} -DenyAddAndCustomizePages:$false
|
>
|
||||||
|
> ```powershell
|
||||||
|
> Set-PnPTenantSite -Identity {SiteUrl} -DenyAddAndCustomizePages:$false
|
||||||
|
> ```
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
This project consists of two webparts that can be used to manage the Property Bags for SharePoint sites and two webparts that can be used to display navigational components from those Properties.
|
|
||||||
|
|
||||||
- PropertyBagEditor
|
This project consists of two web parts that can be used to manage the Property Bags for SharePoint sites and two web parts that can be used to display navigational components from those Properties.
|
||||||
|
|
||||||
|
* PropertyBagEditor
|
||||||
This web part allows a site owner/administrator to edit selected items in a site's Property Bag. It edits the properties of the current site. A sample display is shown below:
|
This web part allows a site owner/administrator to edit selected items in a site's Property Bag. It edits the properties of the current site. A sample display is shown below:
|
||||||
![PropertyBagEditorDisplay](./src/images/PropertyBagEditorDisplay.PNG)
|
![PropertyBagEditorDisplay](./assets/PropertyBagEditorDisplay.PNG)
|
||||||
|
|
||||||
Selecting a Property and clicking the Edit button will bring up the Edit Panel:
|
Selecting a Property and clicking the Edit button will bring up the Edit Panel:
|
||||||
|
|
||||||
![PropertyBagEditorEdur](./src/images/PropertyBagEditorEdit.PNG)
|
![PropertyBagEditorEdur](./assets/PropertyBagEditorEdit.PNG)
|
||||||
|
|
||||||
Here you can change the value of the property and specify if the property should be included in the search Index.
|
Here you can change the value of the property and specify if the property should be included in the search Index.
|
||||||
|
|
||||||
The Properties that can be edited are specified in the web part's Property Pane:
|
The Properties that can be edited are specified in the web part's Property Pane:
|
||||||
|
|
||||||
![PropertyBagEditorEdur](./src/images/PropertyBagEditorConfig.PNG)
|
![PropertyBagEditorEdur](./assets/PropertyBagEditorConfig.PNG)
|
||||||
|
|
||||||
|
The Properties set in the Property Pane of this web part are crawled properties, and should be mapped to managed properties so that can be used by the other web parts in this project.
|
||||||
The Properties set in the Property Pane of this web part are crawled properties, and should be mapped to managed properties so that can be used by the other webparts in this project.
|
|
||||||
|
|
||||||
The Site whose properties are to be edited can be passed in via a query parameter. While this web part can be added to any page, it would be most useful if added to a page in an infrastructure site collection in the tenant, and then linked to from all other sites via a link in the Site Settings page.
|
The Site whose properties are to be edited can be passed in via a query parameter. While this web part can be added to any page, it would be most useful if added to a page in an infrastructure site collection in the tenant, and then linked to from all other sites via a link in the Site Settings page.
|
||||||
|
|
||||||
The following script shows how to add such a link to all sites 'Site Settings' page using PNP Powershell. It will add a menu item named 'Edit Site Metadata ' to the Site Settings of each Team Site that links to the PropertBagEdcitor.aspx page on the tenants infrastructure site (this site is named 'cdn' in the example below).
|
The following script shows how to add such a link to all sites 'Site Settings' page using PNP PowerShell. It will add a menu item named 'Edit Site Metadata ' to the Site Settings of each Team Site that links to the PropertyBagEditor.aspx page on the tenants infrastructure site (this site is named 'cdn' in the example below).
|
||||||
|
|
||||||
```
|
```powershell
|
||||||
$adminSiteUrl="https://tenant-admin.sharepoint.com"
|
$adminSiteUrl="https://tenant-admin.sharepoint.com"
|
||||||
|
|
||||||
$customActionDescription="CUSTOM_\ ___Navigation__ \__Metadata"
|
$customActionDescription="CUSTOM_\ ___Navigation__ \__Metadata"
|
||||||
|
|
||||||
$pageUrl="https://tenant.sharepoint.com/sites/cdn/SitePages/PropertBagEdcitor.aspx?siteUrl={0}"
|
$pageUrl="https://tenant.sharepoint.com/sites/cdn/SitePages/PropertyBagEditor.aspx?siteUrl={0}"
|
||||||
|
|
||||||
$credentials=get-credential
|
$credentials=get-credential
|
||||||
|
|
||||||
|
@ -126,49 +125,47 @@ foreach($site in $sites){
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- PropertyBagDisplay
|
* PropertyBagDisplay
|
||||||
The propertyBagDisplay web part can be used by an administrator to view and edit selected properties across sites in the tenant:
|
The propertyBagDisplay web part can be used by an administrator to view and edit selected properties across sites in the tenant:
|
||||||
|
|
||||||
![PropertyBagDisplay](./src/images/PropertyBagDisplayDisplay.PNG)
|
![PropertyBagDisplay](./assets/PropertyBagDisplayDisplay.PNG)
|
||||||
|
|
||||||
In the Property Pane, an administrator must specify both the Crawled Property Name and the Managed Property name (separated by a pipe character) of the properties to be included in the web part:
|
In the Property Pane, an administrator must specify both the Crawled Property Name and the Managed Property name (separated by a pipe character) of the properties to be included in the web part:
|
||||||
|
|
||||||
![PropertyBagDisplayConfig](./src/images/PropertBagDisplayConfig.PNG)
|
![PropertyBagDisplayConfig](./assets/PropertBagDisplayConfig.PNG)
|
||||||
|
|
||||||
The administrator can also include a list of site templates to narrow down the list of sites to be included in the web part. When specifying site templates to include you can include just the Site Template Name (STS) and all sites within that template name will be included, or you can specify the Site Template Name and ID, separated by a '#" character (STS#1) to have only sites with that template name and ID included.
|
The administrator can also include a list of site templates to narrow down the list of sites to be included in the web part. When specifying site templates to include you can include just the Site Template Name (STS) and all sites within that template name will be included, or you can specify the Site Template Name and ID, separated by a '#" character (STS#1) to have only sites with that template name and ID included.
|
||||||
|
|
||||||
The web part displays the site template, Title and Url, plus the selected Managed Properties for all sites in the tenant with the selected site template. The Managed Properties are only displayed if they have been set as searchable, and a full crawl has been run. After selecting a Site, a user can click the edit button to edit the Crawled properties (i.e. the raw property bag values) for the selected site:
|
The web part displays the site template, Title and URL, plus the selected Managed Properties for all sites in the tenant with the selected site template. The Managed Properties are only displayed if they have been set as searchable, and a full crawl has been run. After selecting a Site, a user can click the edit button to edit the Crawled properties (i.e. the raw property bag values) for the selected site:
|
||||||
|
|
||||||
![PropertyBagDisplayEdit](./src/images/PropertyBagDisplayEdit.PNG)
|
![PropertyBagDisplayEdit](./assets/PropertyBagDisplayEdit.PNG)
|
||||||
|
|
||||||
On the edit panel one can specify a new value for each property as well as whether that property is to be included in the search index. Additionally one can specify that a full crawl of the site should be run once the properties are saved.
|
On the edit panel one can specify a new value for each property as well as whether that property is to be included in the search index. Additionally one can specify that a full crawl of the site should be run once the properties are saved.
|
||||||
|
|
||||||
- PropertyBagFilteredSiteList
|
* PropertyBagFilteredSiteList
|
||||||
This web part displays a list of all sites that meet the criteria specified in the property pane by the administrator:
|
This web part displays a list of all sites that meet the criteria specified in the property pane by the administrator:
|
||||||
|
|
||||||
![PropertyBagFilteredSiteListDisplay](./src/images/PropertyBagFilteredSiteListDisplay.PNG)
|
![PropertyBagFilteredSiteListDisplay](./assets/PropertyBagFilteredSiteListDisplay.PNG)
|
||||||
|
|
||||||
Additionally, it lets the user narrow down the list of sites displayed by applying metadata filters that are set up by the administrator in the Property Pane( Business Unit and Continent in the example above):
|
Additionally, it lets the user narrow down the list of sites displayed by applying metadata filters that are set up by the administrator in the Property Pane( Business Unit and Continent in the example above):
|
||||||
|
|
||||||
![PropertyBagFilteredSiteListConfig](./src/images/PropertyBagFilteredSiteListConfigy.PNG)
|
![PropertyBagFilteredSiteListConfig](./assets/PropertyBagFilteredSiteListConfigy.PNG)
|
||||||
|
|
||||||
In the PropertyPane above, the 'Site Templates to Include' and 'Metadata Filters' are used to filter which site collections are retrieved from search. The 'User Filters' are used to allow the user to easily filter the results returned from search using the command bar on the top of the display.
|
In the PropertyPane above, the 'Site Templates to Include' and 'Metadata Filters' are used to filter which site collections are retrieved from search. The 'User Filters' are used to allow the user to easily filter the results returned from search using the command bar on the top of the display.
|
||||||
|
|
||||||
- PropertyBagGlobalNav
|
* PropertyBagGlobalNav
|
||||||
This Web part builds a navigation menu based on the Managed Properties set up in the PropertyPane:
|
This Web part builds a navigation menu based on the Managed Properties set up in the PropertyPane:
|
||||||
|
|
||||||
![propertyBagGlobalNavDisplay](./src/images/propertyBagGlobalNavDisplay.PNG)
|
![propertyBagGlobalNavDisplay](./assets/propertyBagGlobalNavDisplay.PNG)
|
||||||
|
|
||||||
In the PropertyPane, an administrator just needs to specify which Managed Properties are to be used to build the Navigation menu:
|
In the PropertyPane, an administrator just needs to specify which Managed Properties are to be used to build the Navigation menu:
|
||||||
|
|
||||||
![PropertyBagGlobalNavConfig](./src/images/PropertyBagGlobalNavConfig.PNG)
|
![PropertyBagGlobalNavConfig](./assets/PropertyBagGlobalNavConfig.PNG)
|
||||||
|
|
||||||
If desired, the admin can also specify which site templates should be included in the menu, as wall as any additional filters. Additional Filters can be specified in the format 'ManagedPropertyName=value';
|
If desired, the admin can also specify which site templates should be included in the menu, as wall as any additional filters. Additional Filters can be specified in the format 'ManagedPropertyName=value';
|
||||||
|
|
||||||
|
|
||||||
## Disclaimer
|
## Disclaimer
|
||||||
|
|
||||||
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
|
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
|
||||||
|
|
||||||
|
|
||||||
<img src="https://m365-visitor-stats.azurewebsites.net/sp-dev-fx-webparts/samples/react-property-bag-editor" />
|
<img src="https://m365-visitor-stats.azurewebsites.net/sp-dev-fx-webparts/samples/react-property-bag-editor" />
|
||||||
|
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
@ -2,14 +2,14 @@
|
||||||
{
|
{
|
||||||
"name": "pnp-sp-dev-spfx-web-parts-react-property-bag-editor",
|
"name": "pnp-sp-dev-spfx-web-parts-react-property-bag-editor",
|
||||||
"source": "pnp",
|
"source": "pnp",
|
||||||
"title": "Property Bag Navigation Webparts",
|
"title": "Property Bag Navigation Web parts",
|
||||||
"shortDescription": "A set of webparts that lets you set property bag settings on site collections and enable navigation using those properties.",
|
"shortDescription": "A set of web parts that lets you set property bag settings on site collections and enable navigation using those properties.",
|
||||||
"url": "https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-property-bag-editor",
|
"url": "https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-property-bag-editor",
|
||||||
"longDescription": [
|
"longDescription": [
|
||||||
"A set of webparts that lets you set property bag settings on site collections and enable navigation using those properties."
|
"A set of web parts that lets you set property bag settings on site collections and enable navigation using those properties."
|
||||||
],
|
],
|
||||||
"creationDateTime": "2017-03-19",
|
"creationDateTime": "2017-03-19",
|
||||||
"updateDateTime": "2017-03-19",
|
"updateDateTime": "2024-02-21",
|
||||||
"products": [
|
"products": [
|
||||||
"SharePoint"
|
"SharePoint"
|
||||||
],
|
],
|
||||||
|
@ -27,14 +27,13 @@
|
||||||
{
|
{
|
||||||
"type": "image",
|
"type": "image",
|
||||||
"order": 100,
|
"order": 100,
|
||||||
"url": "https://github.com/pnp/sp-dev-fx-webparts/raw/main/samples/react-property-bag-editor/src/images/PropertyBagEditorDisplay.PNG",
|
"url": "https://github.com/pnp/sp-dev-fx-webparts/raw/main/samples/react-property-bag-editor/assets/PropertyBagEditorDisplay.PNG",
|
||||||
"alt": "Property Bag Navigation Webparts"
|
"alt": "Property Bag Navigation Web parts"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"gitHubAccount": "russgove",
|
"gitHubAccount": "russgove",
|
||||||
"company": "",
|
|
||||||
"pictureUrl": "https://github.com/russgove.png",
|
"pictureUrl": "https://github.com/russgove.png",
|
||||||
"name": "Russell Gove"
|
"name": "Russell Gove"
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,7 @@ export default class PropertyBagDisplayWebPart extends BaseClientSideWebPart<IPr
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// eslint-disable-next-line @microsoft/spfx/pair-react-dom-render-unmount
|
||||||
ReactDom.render(element, this.domElement);
|
ReactDom.render(element, this.domElement);
|
||||||
}
|
}
|
||||||
public onInit(): Promise<void> {
|
public onInit(): Promise<void> {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||||
import * as _ from "lodash";
|
import * as _ from "lodash";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import pnp, { SearchQuery, SearchResults, Web } from "sp-pnp-js";
|
import pnp, { SearchQuery, SearchResults, Web } from "sp-pnp-js";
|
||||||
|
@ -23,9 +24,10 @@ import {
|
||||||
} from "office-ui-fabric-react/lib/Panel";
|
} from "office-ui-fabric-react/lib/Panel";
|
||||||
export interface IPropertyBagDisplayState {
|
export interface IPropertyBagDisplayState {
|
||||||
selectedIndex: number; // the currently selected site
|
selectedIndex: number; // the currently selected site
|
||||||
managedToCrawedMapping?: Array<ManagedToCrawledMappingEntry>;// Determines which Carwled propeties are mapped to which Managed Properties
|
managedToCrawedMapping?: Array<ManagedToCrawledMappingEntry>;// Determines which Crawled properties are mapped to which Managed Properties
|
||||||
errorMessages: Array<md.Message>; // a list of error massages displayed on the page
|
errorMessages: Array<md.Message>; // a list of error massages displayed on the page
|
||||||
isediting?: boolean; //Determines if the edit panel is displayed
|
isediting?: boolean; //Determines if the edit panel is displayed
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
sites: Array<any>; // the list of sites displayed in the component
|
sites: Array<any>; // the list of sites displayed in the component
|
||||||
workingStorage?: DisplaySite;// A working copy of the site being edited
|
workingStorage?: DisplaySite;// A working copy of the site being edited
|
||||||
managedPropNames?: Array<string>; // the list of managed properties to be displayed
|
managedPropNames?: Array<string>; // the list of managed properties to be displayed
|
||||||
|
@ -171,8 +173,8 @@ export default class PropertyBagDisplay extends React.Component<IPropertyBagDisp
|
||||||
/**
|
/**
|
||||||
* Removes a message from the MessageDIsplay when the user click the 'x'
|
* Removes a message from the MessageDIsplay when the user click the 'x'
|
||||||
*
|
*
|
||||||
* @param {Array<md.Message>} messageList The list to remove the masseg from (the 'main' window of the Panel)
|
* @param {Array<md.Message>} messageList The list to remove the message from (the 'main' window of the Panel)
|
||||||
* @param {string} messageId The Id of the massge to remove
|
* @param {string} messageId The Id of the message to remove
|
||||||
*
|
*
|
||||||
* @memberOf PropertyBagDisplay
|
* @memberOf PropertyBagDisplay
|
||||||
*/
|
*/
|
||||||
|
@ -183,7 +185,7 @@ export default class PropertyBagDisplay extends React.Component<IPropertyBagDisp
|
||||||
this.setState((current) => ({ ...current, errorMessages: messageList }));
|
this.setState((current) => ({ ...current, errorMessages: messageList }));
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Removes a massage from the main windo
|
* Removes a massage from the main window
|
||||||
*
|
*
|
||||||
* @param {string} messageId
|
* @param {string} messageId
|
||||||
*
|
*
|
||||||
|
@ -212,9 +214,10 @@ export default class PropertyBagDisplay extends React.Component<IPropertyBagDisp
|
||||||
*
|
*
|
||||||
* @memberOf PropertyBagDisplay
|
* @memberOf PropertyBagDisplay
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
private changeSearchable(siteUrl: string, propname: string, newValue: boolean): Promise<any> {
|
private changeSearchable(siteUrl: string, propname: string, newValue: boolean): Promise<any> {
|
||||||
if (newValue) {//make prop searchable
|
if (newValue) {//make prop searchable
|
||||||
if (_.indexOf(this.state.workingStorage.searchableProps, propname) === -1) {// wasa not searchable, mpw it is
|
if (_.indexOf(this.state.workingStorage.searchableProps, propname) === -1) {// was not searchable, now it is
|
||||||
console.log(propname + "was not searchable, now it is ");
|
console.log(propname + "was not searchable, now it is ");
|
||||||
this.state.workingStorage.searchableProps.push(propname);
|
this.state.workingStorage.searchableProps.push(propname);
|
||||||
return utils.saveSearchablePropertiesToSharePoint(siteUrl, this.state.workingStorage.searchableProps);
|
return utils.saveSearchablePropertiesToSharePoint(siteUrl, this.state.workingStorage.searchableProps);
|
||||||
|
@ -224,8 +227,8 @@ export default class PropertyBagDisplay extends React.Component<IPropertyBagDisp
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else { // make prop not searchablke
|
else { // make prop not searchable
|
||||||
if (_.indexOf(this.state.workingStorage.searchableProps, propname) !== -1) {// wasa not searchable, mpw it is
|
if (_.indexOf(this.state.workingStorage.searchableProps, propname) !== -1) {// was not searchable, now it is
|
||||||
console.log(propname + "was searchable, now it is not");
|
console.log(propname + "was searchable, now it is not");
|
||||||
_.remove(this.state.workingStorage.searchableProps, p => { return p === propname; });
|
_.remove(this.state.workingStorage.searchableProps, p => { return p === propname; });
|
||||||
return utils.saveSearchablePropertiesToSharePoint(siteUrl, this.state.workingStorage.searchableProps);
|
return utils.saveSearchablePropertiesToSharePoint(siteUrl, this.state.workingStorage.searchableProps);
|
||||||
|
@ -250,7 +253,7 @@ export default class PropertyBagDisplay extends React.Component<IPropertyBagDisp
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* Caled by the Details list to render a column as a URL rather than text
|
* Called by the Details list to render a column as a URL rather than text
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @param {*} [item]
|
* @param {*} [item]
|
||||||
|
@ -260,6 +263,7 @@ export default class PropertyBagDisplay extends React.Component<IPropertyBagDisp
|
||||||
*
|
*
|
||||||
* @memberOf PropertyBagDisplay
|
* @memberOf PropertyBagDisplay
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
private renderSiteUrl(item?: any, index?: number, column?: IColumn): JSX.Element {
|
private renderSiteUrl(item?: any, index?: number, column?: IColumn): JSX.Element {
|
||||||
return (<a href={item[column.fieldName]}>{item[column.fieldName]} </a>);
|
return (<a href={item[column.fieldName]}>{item[column.fieldName]} </a>);
|
||||||
}
|
}
|
||||||
|
@ -268,7 +272,7 @@ export default class PropertyBagDisplay extends React.Component<IPropertyBagDisp
|
||||||
/**
|
/**
|
||||||
* Sets the columns to be displayed in the list.
|
* Sets the columns to be displayed in the list.
|
||||||
* These are SiteTemplate, Title and Url, plus any properties specified in
|
* These are SiteTemplate, Title and Url, plus any properties specified in
|
||||||
* the propertypane
|
* the property pane
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
* @returns {Array<IColumn>}
|
* @returns {Array<IColumn>}
|
||||||
|
@ -321,15 +325,15 @@ export default class PropertyBagDisplay extends React.Component<IPropertyBagDisp
|
||||||
}
|
}
|
||||||
/** react lifecycle */
|
/** react lifecycle */
|
||||||
/**
|
/**
|
||||||
* Called when the componet loads.
|
* Called when the component loads.
|
||||||
* Builds the query to search sharepoint for the list of sites to display and formates
|
* Builds the query to search sharepoint for the list of sites to display and formats
|
||||||
* the results to be displayed in the list
|
* the results to be displayed in the list
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* @memberOf PropertyBagDisplay
|
* @memberOf PropertyBagDisplay
|
||||||
*/
|
*/
|
||||||
public componentDidMount(): void {
|
public componentDidMount(): void {
|
||||||
let initState = {
|
const initState = {
|
||||||
|
|
||||||
columns: this.setupColumns(),
|
columns: this.setupColumns(),
|
||||||
managedToCrawedMapping: [],
|
managedToCrawedMapping: [],
|
||||||
|
@ -338,7 +342,7 @@ export default class PropertyBagDisplay extends React.Component<IPropertyBagDisp
|
||||||
errorMessages: []
|
errorMessages: []
|
||||||
};
|
};
|
||||||
for (const prop of this.props.propertiesToDisplay) {
|
for (const prop of this.props.propertiesToDisplay) {
|
||||||
const names: Array<string> = prop.split('|');// crawledpropety/managed property
|
const names: Array<string> = prop.split('|');// crawled property/managed property
|
||||||
initState.managedToCrawedMapping.push(new ManagedToCrawledMappingEntry(names[0], names[1]));
|
initState.managedToCrawedMapping.push(new ManagedToCrawledMappingEntry(names[0], names[1]));
|
||||||
initState.managedPropNames.push(names[1]);
|
initState.managedPropNames.push(names[1]);
|
||||||
}
|
}
|
||||||
|
@ -372,6 +376,7 @@ export default class PropertyBagDisplay extends React.Component<IPropertyBagDisp
|
||||||
};
|
};
|
||||||
pnp.sp.search(q).then((results: SearchResults) => {
|
pnp.sp.search(q).then((results: SearchResults) => {
|
||||||
for (const r of results.PrimarySearchResults) {
|
for (const r of results.PrimarySearchResults) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const obj: any = {};
|
const obj: any = {};
|
||||||
for (const dp of initState.managedPropNames) {
|
for (const dp of initState.managedPropNames) {
|
||||||
obj[dp] = r[dp];
|
obj[dp] = r[dp];
|
||||||
|
@ -396,6 +401,7 @@ export default class PropertyBagDisplay extends React.Component<IPropertyBagDisp
|
||||||
*
|
*
|
||||||
* @memberOf PropertyBagDisplay
|
* @memberOf PropertyBagDisplay
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
private onActiveItemChanged(item?: any, index?: number): void {
|
private onActiveItemChanged(item?: any, index?: number): void {
|
||||||
this.setState((current) => ({ ...current, selectedIndex: index }));
|
this.setState((current) => ({ ...current, selectedIndex: index }));
|
||||||
}
|
}
|
||||||
|
@ -408,6 +414,7 @@ export default class PropertyBagDisplay extends React.Component<IPropertyBagDisp
|
||||||
* @memberOf PropertyBagDisplay
|
* @memberOf PropertyBagDisplay
|
||||||
*/
|
*/
|
||||||
private onSave(e?: MouseEvent): void {
|
private onSave(e?: MouseEvent): void {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
const promises: Array<Promise<any>> = [];
|
const promises: Array<Promise<any>> = [];
|
||||||
for (const prop of this.state.workingStorage.DisplayProps) {
|
for (const prop of this.state.workingStorage.DisplayProps) {
|
||||||
const promise = utils.setSPProperty(prop.crawledPropertyName, prop.value, this.state.workingStorage.Url)
|
const promise = utils.setSPProperty(prop.crawledPropertyName, prop.value, this.state.workingStorage.Url)
|
||||||
|
@ -417,8 +424,10 @@ export default class PropertyBagDisplay extends React.Component<IPropertyBagDisp
|
||||||
promises.push(promise);
|
promises.push(promise);
|
||||||
}
|
}
|
||||||
Promise.all(promises)
|
Promise.all(promises)
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
.then((results: Array<any>) => {
|
.then((results: Array<any>) => {
|
||||||
if (this.state.workingStorage.forceCrawl) {
|
if (this.state.workingStorage.forceCrawl) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
utils.forceCrawl(this.state.workingStorage.Url);
|
utils.forceCrawl(this.state.workingStorage.Url);
|
||||||
}
|
}
|
||||||
debugger;
|
debugger;
|
||||||
|
@ -463,7 +472,7 @@ export default class PropertyBagDisplay extends React.Component<IPropertyBagDisp
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when user wishes to edit an item.
|
* Called when user wishes to edit an item.
|
||||||
* The List displayes the values from the search index.
|
* The List displays the values from the search index.
|
||||||
* This method gets the values from the actual PropertyBag so that they can be edited.
|
* This method gets the values from the actual PropertyBag so that they can be edited.
|
||||||
*
|
*
|
||||||
* @param {MouseEvent} [e]
|
* @param {MouseEvent} [e]
|
||||||
|
@ -476,11 +485,13 @@ export default class PropertyBagDisplay extends React.Component<IPropertyBagDisp
|
||||||
const selectedSite = this.state.sites[this.state.selectedIndex];
|
const selectedSite = this.state.sites[this.state.selectedIndex];
|
||||||
const web = new Web(selectedSite.Url);
|
const web = new Web(selectedSite.Url);
|
||||||
// let context = this;
|
// let context = this;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
web.select("Title", "AllProperties").expand("AllProperties").get().then((r) => {
|
web.select("Title", "AllProperties").expand("AllProperties").get().then((r) => {
|
||||||
const crawledProps: Array<string> = this.props.propertiesToDisplay.map(item => {
|
const crawledProps: Array<string> = this.props.propertiesToDisplay.map(item => {
|
||||||
return item.split("|")[0];
|
return item.split("|")[0];
|
||||||
});
|
});
|
||||||
let temp = _.clone(selectedSite);
|
const temp = _.clone(selectedSite);
|
||||||
|
// eslint-disable-next-line dot-notation
|
||||||
temp.searchableProps = utils.decodeSearchableProps(r.AllProperties["vti_x005f_indexedpropertykeys"]);
|
temp.searchableProps = utils.decodeSearchableProps(r.AllProperties["vti_x005f_indexedpropertykeys"]);
|
||||||
temp.DisplayProps = utils.SelectProperties(r.AllProperties, crawledProps, temp.searchableProps);
|
temp.DisplayProps = utils.SelectProperties(r.AllProperties, crawledProps, temp.searchableProps);
|
||||||
temp.errorMessages = new Array<md.Message>();
|
temp.errorMessages = new Array<md.Message>();
|
||||||
|
@ -506,6 +517,7 @@ export default class PropertyBagDisplay extends React.Component<IPropertyBagDisp
|
||||||
*
|
*
|
||||||
* @memberOf PropertyBagDisplay
|
* @memberOf PropertyBagDisplay
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type, @typescript-eslint/no-explicit-any
|
||||||
private _onColumnClick(event: any, column: IColumn) {
|
private _onColumnClick(event: any, column: IColumn) {
|
||||||
column = _.find(this.state.columns, c => c.fieldName === column.fieldName);// find the object in state
|
column = _.find(this.state.columns, c => c.fieldName === column.fieldName);// find the object in state
|
||||||
// If we've sorted this column, flip it.
|
// If we've sorted this column, flip it.
|
||||||
|
@ -517,7 +529,7 @@ export default class PropertyBagDisplay extends React.Component<IPropertyBagDisp
|
||||||
column.isSortedDescending = false;
|
column.isSortedDescending = false;
|
||||||
}
|
}
|
||||||
// Sort the items.
|
// Sort the items.
|
||||||
let temp = _.orderBy(this.state.sites, (site) => {
|
const temp = _.orderBy(this.state.sites, (site) => {
|
||||||
if (site[column.fieldName]) {
|
if (site[column.fieldName]) {
|
||||||
return site[column.fieldName].toLowerCase();
|
return site[column.fieldName].toLowerCase();
|
||||||
}
|
}
|
||||||
|
@ -558,8 +570,7 @@ export default class PropertyBagDisplay extends React.Component<IPropertyBagDisp
|
||||||
checkboxVisibility={CheckboxVisibility.hidden}
|
checkboxVisibility={CheckboxVisibility.hidden}
|
||||||
onActiveItemChanged={this.onActiveItemChanged.bind(this)
|
onActiveItemChanged={this.onActiveItemChanged.bind(this)
|
||||||
}
|
}
|
||||||
>
|
/>
|
||||||
</DetailsList>
|
|
||||||
{this.renderPopup.bind(this)()}
|
{this.renderPopup.bind(this)()}
|
||||||
</div >
|
</div >
|
||||||
);
|
);
|
||||||
|
|
|
@ -46,6 +46,7 @@ export default class PropertyBagEditorWebPart extends BaseClientSideWebPart<IPro
|
||||||
props
|
props
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// eslint-disable-next-line @microsoft/spfx/pair-react-dom-render-unmount
|
||||||
ReactDom.render(element, this.domElement);
|
ReactDom.render(element, this.domElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
/* eslint-disable react/no-deprecated */
|
||||||
|
/* eslint-disable @typescript-eslint/explicit-function-return-type */
|
||||||
import * as _ from "lodash";
|
import * as _ from "lodash";
|
||||||
import { DefaultButton, PrimaryButton } from "office-ui-fabric-react/lib/Button";
|
import { DefaultButton, PrimaryButton } from "office-ui-fabric-react/lib/Button";
|
||||||
import { CommandBar } from "office-ui-fabric-react/lib/CommandBar";
|
import { CommandBar } from "office-ui-fabric-react/lib/CommandBar";
|
||||||
|
@ -31,6 +33,7 @@ export interface IPropertyBagEditorState {
|
||||||
export default class PropertyBagEditor extends React.Component<IPropertyBagEditorProps, IPropertyBagEditorState> {
|
export default class PropertyBagEditor extends React.Component<IPropertyBagEditorProps, IPropertyBagEditorState> {
|
||||||
public refs: {
|
public refs: {
|
||||||
[key: string]: React.ReactInstance;
|
[key: string]: React.ReactInstance;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
list: any //DetailsList
|
list: any //DetailsList
|
||||||
};
|
};
|
||||||
public constructor(props: IPropertyBagEditorProps) {
|
public constructor(props: IPropertyBagEditorProps) {
|
||||||
|
@ -58,7 +61,7 @@ export default class PropertyBagEditor extends React.Component<IPropertyBagEdito
|
||||||
onClick: this.onEditItemClicked.bind(this),
|
onClick: this.onEditItemClicked.bind(this),
|
||||||
icon: "Edit"
|
icon: "Edit"
|
||||||
}];
|
}];
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if an item is selected.
|
* Determines if an item is selected.
|
||||||
|
@ -69,13 +72,14 @@ export default class PropertyBagEditor extends React.Component<IPropertyBagEdito
|
||||||
*/
|
*/
|
||||||
get ItemIsSelected(): boolean {
|
get ItemIsSelected(): boolean {
|
||||||
if (!this.state) { return false; }
|
if (!this.state) { return false; }
|
||||||
return (this.state.selectedIndex != -1);
|
return (this.state.selectedIndex !== -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** react lifecycle */
|
/** react lifecycle */
|
||||||
public componentWillMount() {
|
public componentWillMount() {
|
||||||
|
|
||||||
const web = new Web(this.props.siteUrl);
|
const web = new Web(this.props.siteUrl);
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
web.select("Title", "AllProperties").expand("AllProperties").get().then(r => {
|
web.select("Title", "AllProperties").expand("AllProperties").get().then(r => {
|
||||||
debugger;
|
debugger;
|
||||||
const sp = utils.decodeSearchableProps(r.AllProperties.vti_x005f_indexedpropertykeys);
|
const sp = utils.decodeSearchableProps(r.AllProperties.vti_x005f_indexedpropertykeys);
|
||||||
|
@ -84,11 +88,12 @@ export default class PropertyBagEditor extends React.Component<IPropertyBagEdito
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** event hadlers */
|
/** event handlers */
|
||||||
private stopediting() {
|
private stopediting() {
|
||||||
|
|
||||||
this.setState((current) => ({ ...current, isediting: false }))
|
this.setState((current) => ({ ...current, isediting: false }))
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
private onActiveItemChanged(item?: any, index?: number) {
|
private onActiveItemChanged(item?: any, index?: number) {
|
||||||
this.setState((current) => ({ ...current, selectedIndex: index }))
|
this.setState((current) => ({ ...current, selectedIndex: index }))
|
||||||
}
|
}
|
||||||
|
@ -143,8 +148,10 @@ export default class PropertyBagEditor extends React.Component<IPropertyBagEdito
|
||||||
*/
|
*/
|
||||||
private onSave(e?: MouseEvent): void {
|
private onSave(e?: MouseEvent): void {
|
||||||
debugger;
|
debugger;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
utils.setSPProperty(this.state.workingStorage.crawledPropertyName, this.state.workingStorage.value, this.props.siteUrl)
|
utils.setSPProperty(this.state.workingStorage.crawledPropertyName, this.state.workingStorage.value, this.props.siteUrl)
|
||||||
.then(value => {
|
.then(value => {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
this.changeSearchable(this.state.workingStorage.crawledPropertyName, this.state.workingStorage.searchable)
|
this.changeSearchable(this.state.workingStorage.crawledPropertyName, this.state.workingStorage.searchable)
|
||||||
.then(s => {
|
.then(s => {
|
||||||
const temp = _.clone(this.state.displayProps);// this.state.workingStorage = null;
|
const temp = _.clone(this.state.displayProps);// this.state.workingStorage = null;
|
||||||
|
@ -174,6 +181,7 @@ export default class PropertyBagEditor extends React.Component<IPropertyBagEdito
|
||||||
*
|
*
|
||||||
* @memberOf PropertyBagEditor
|
* @memberOf PropertyBagEditor
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
private changeSearchable(propname: string, newValue: boolean): Promise<any> {
|
private changeSearchable(propname: string, newValue: boolean): Promise<any> {
|
||||||
if (newValue) {//make prop searchable
|
if (newValue) {//make prop searchable
|
||||||
if (_.indexOf(this.state.searchableProps, propname) === -1) {// wasa not searchable, mpw it is
|
if (_.indexOf(this.state.searchableProps, propname) === -1) {// wasa not searchable, mpw it is
|
||||||
|
@ -199,6 +207,7 @@ export default class PropertyBagEditor extends React.Component<IPropertyBagEdito
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
private RenderBoolean(item?: any, index?: number, column?: IColumn): any {
|
private RenderBoolean(item?: any, index?: number, column?: IColumn): any {
|
||||||
if (item[column.fieldName]) {
|
if (item[column.fieldName]) {
|
||||||
return (<div>Yes</div>);
|
return (<div>Yes</div>);
|
||||||
|
@ -229,8 +238,7 @@ export default class PropertyBagEditor extends React.Component<IPropertyBagEdito
|
||||||
checkboxVisibility={CheckboxVisibility.hidden}
|
checkboxVisibility={CheckboxVisibility.hidden}
|
||||||
items={this.state.displayProps}
|
items={this.state.displayProps}
|
||||||
onActiveItemChanged={this.onActiveItemChanged.bind(this)}
|
onActiveItemChanged={this.onActiveItemChanged.bind(this)}
|
||||||
>
|
/>
|
||||||
</DetailsList>
|
|
||||||
<Dialog
|
<Dialog
|
||||||
hidden={!this.state.isediting} type={DialogType.close}
|
hidden={!this.state.isediting} type={DialogType.close}
|
||||||
onDismiss={this.stopediting.bind(this)}
|
onDismiss={this.stopediting.bind(this)}
|
||||||
|
|
|
@ -39,6 +39,7 @@ export default class PropertyBagFilteredSiteListWebPart extends BaseClientSideWe
|
||||||
showQueryText: this.properties.showQueryText
|
showQueryText: this.properties.showQueryText
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
// eslint-disable-next-line @microsoft/spfx/pair-react-dom-render-unmount
|
||||||
ReactDom.render(element, this.domElement);
|
ReactDom.render(element, this.domElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable dot-notation */
|
||||||
import * as _ from "lodash";
|
import * as _ from "lodash";
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import pnp, { SearchQuery, SearchResults } from "sp-pnp-js";
|
import pnp, { SearchQuery, SearchResults } from "sp-pnp-js";
|
||||||
|
@ -168,9 +169,9 @@ export default class PropertyBagFilteredSiteList extends React.Component<IProper
|
||||||
|
|
||||||
};
|
};
|
||||||
pnp.sp.search(q).then((results: SearchResults) => {
|
pnp.sp.search(q).then((results: SearchResults) => {
|
||||||
let sites = [];
|
const sites = [];
|
||||||
debugger;
|
debugger;
|
||||||
let userFilters: UserFilter[] = [];
|
const userFilters: UserFilter[] = [];
|
||||||
for (const userFilterName of this.props.userFilters) {
|
for (const userFilterName of this.props.userFilters) {
|
||||||
userFilters.push(new UserFilter(userFilterName));
|
userFilters.push(new UserFilter(userFilterName));
|
||||||
}
|
}
|
||||||
|
@ -185,11 +186,11 @@ export default class PropertyBagFilteredSiteList extends React.Component<IProper
|
||||||
this.extractUserFilterValues(userFilters, r);
|
this.extractUserFilterValues(userFilters, r);
|
||||||
}
|
}
|
||||||
debugger;
|
debugger;
|
||||||
let filteredSites = this.filterSites([], sites);// need to pass sites iun here and return the filtered array!!!
|
const filteredSites = this.filterSites([], sites);// need to pass sites iun here and return the filtered array!!!
|
||||||
this.setState((current) => ({ ...current, filteredSites: filteredSites, sites: sites, userFilters: userFilters }));
|
this.setState((current) => ({ ...current, filteredSites: filteredSites, sites: sites, userFilters: userFilters }));
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
debugger;
|
debugger;
|
||||||
let errorMessages = this.state.errorMessages;
|
const errorMessages = this.state.errorMessages;
|
||||||
errorMessages.push(new md.Message(err));
|
errorMessages.push(new md.Message(err));
|
||||||
this.setState((current => ({ ...current, errorMessages: errorMessages })));
|
this.setState((current => ({ ...current, errorMessages: errorMessages })));
|
||||||
});
|
});
|
||||||
|
@ -208,7 +209,7 @@ export default class PropertyBagFilteredSiteList extends React.Component<IProper
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by the Render method.
|
* Called by the Render method.
|
||||||
* Displayes the Site Description if requested in the PropertyPane.
|
* Displays the Site Description if requested in the PropertyPane.
|
||||||
* Otherwise displays an empty Div
|
* Otherwise displays an empty Div
|
||||||
*
|
*
|
||||||
* @param {Site} site
|
* @param {Site} site
|
||||||
|
@ -337,12 +338,13 @@ export default class PropertyBagFilteredSiteList extends React.Component<IProper
|
||||||
* Applies the new Filters.
|
* Applies the new Filters.
|
||||||
* re-deiplays the list
|
* re-deiplays the list
|
||||||
*
|
*
|
||||||
* @param {React.MouseEvent<HTMLElement>} [ev]
|
* @param {React.MouseEvent<HTMLElement>} [_ev]
|
||||||
* @param {IContextualMenuItem} [item]
|
* @param {IContextualMenuItem} [item]
|
||||||
*
|
*
|
||||||
* @memberOf PropertyBagFilteredSiteList
|
* @memberOf PropertyBagFilteredSiteList
|
||||||
*/
|
*/
|
||||||
private filterOnMetadata(ev?: React.MouseEvent<HTMLElement>, item?: IContextualMenuItem) {
|
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||||
|
private filterOnMetadata(_ev?: React.MouseEvent<HTMLElement>, item?: IContextualMenuItem) {
|
||||||
const newFilters = this.ToggleAppliedUserFilter(this.state.appliedUserFilters, item);
|
const newFilters = this.ToggleAppliedUserFilter(this.state.appliedUserFilters, item);
|
||||||
this.setState((current) => ({ ...current, appliedUserFilters: newFilters, filteredSites: this.filterSites(newFilters, current.sites) }));
|
this.setState((current) => ({ ...current, appliedUserFilters: newFilters, filteredSites: this.filterSites(newFilters, current.sites) }));
|
||||||
}
|
}
|
||||||
|
@ -358,7 +360,8 @@ export default class PropertyBagFilteredSiteList extends React.Component<IProper
|
||||||
|
|
||||||
debugger;
|
debugger;
|
||||||
const listItems = this.state.filteredSites.map((site) =>
|
const listItems = this.state.filteredSites.map((site) =>
|
||||||
<li >
|
// eslint-disable-next-line react/jsx-key
|
||||||
|
<li>
|
||||||
<a href={site.url} target={this.props.linkTarget}>{site.title} --{site["AreaName"]} --{site["Continent"]} </a>
|
<a href={site.url} target={this.props.linkTarget}>{site.title} --{site["AreaName"]} --{site["Continent"]} </a>
|
||||||
{this.conditionallyRenderDescription(site)}
|
{this.conditionallyRenderDescription(site)}
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -22,6 +22,7 @@ export default class PropertyBagGlobalNavWebPart extends BaseClientSideWebPart<I
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// eslint-disable-next-line @microsoft/spfx/pair-react-dom-render-unmount
|
||||||
ReactDom.render(element, this.domElement);
|
ReactDom.render(element, this.domElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ export default class PropertyBagGlobalNav extends React.Component<IPropertyBagGl
|
||||||
*
|
*
|
||||||
* @memberOf PropertyBagGlobalNav
|
* @memberOf PropertyBagGlobalNav
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
private addMenuItem(items: Array<IContextualMenuItem>, r: any): Array<IContextualMenuItem> {
|
private addMenuItem(items: Array<IContextualMenuItem>, r: any): Array<IContextualMenuItem> {
|
||||||
let currentItem: IContextualMenuItem;
|
let currentItem: IContextualMenuItem;
|
||||||
let currentSet: Array<IContextualMenuItem> = items;
|
let currentSet: Array<IContextualMenuItem> = items;
|
||||||
|
@ -90,7 +91,7 @@ export default class PropertyBagGlobalNav extends React.Component<IPropertyBagGl
|
||||||
|
|
||||||
};
|
};
|
||||||
pnp.sp.search(q).then((results: SearchResults) => {
|
pnp.sp.search(q).then((results: SearchResults) => {
|
||||||
let menuitems = [];
|
const menuitems = [];
|
||||||
for (const r of results.PrimarySearchResults) {
|
for (const r of results.PrimarySearchResults) {
|
||||||
this.addMenuItem(menuitems, r);
|
this.addMenuItem(menuitems, r);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,7 @@ export interface IMessageDisplayProps {
|
||||||
* @class MessageDisplay
|
* @class MessageDisplay
|
||||||
* @extends {React.Component<IMessageDisplayProps, any>}
|
* @extends {React.Component<IMessageDisplayProps, any>}
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export default class MessageDisplay extends React.Component<IMessageDisplayProps, any> {
|
export default class MessageDisplay extends React.Component<IMessageDisplayProps, any> {
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -36,6 +37,7 @@ export default class MessageDisplay extends React.Component<IMessageDisplayProps
|
||||||
*
|
*
|
||||||
* @memberOf MessageDisplay
|
* @memberOf MessageDisplay
|
||||||
*/
|
*/
|
||||||
|
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
||||||
public createDismissHandler = (messageId) => (vale) => {
|
public createDismissHandler = (messageId) => (vale) => {
|
||||||
this.props.hideMessage(messageId);
|
this.props.hideMessage(messageId);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import * as _ from "lodash";
|
import * as _ from "lodash";
|
||||||
import { Web } from "sp-pnp-js";
|
import { Web } from "sp-pnp-js";
|
||||||
require("sp-init");
|
require("sp-init");
|
||||||
|
@ -7,7 +8,7 @@ require("sharepoint");
|
||||||
import DisplayProp from "./DisplayProp";
|
import DisplayProp from "./DisplayProp";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Various utilitty functions used by the React-ProprtyBag* Webparts
|
* Various utility functions used by the React-PropertyBag* Web parts
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
* @class utils
|
* @class utils
|
||||||
|
@ -27,7 +28,7 @@ export default class utils {
|
||||||
* @memberOf utils
|
* @memberOf utils
|
||||||
*/
|
*/
|
||||||
public static EncodePropertyKey(propKey): string {
|
public static EncodePropertyKey(propKey): string {
|
||||||
let bytes = [];
|
const bytes = [];
|
||||||
for (let i = 0; i < propKey.length; ++i) {
|
for (let i = 0; i < propKey.length; ++i) {
|
||||||
bytes.push(propKey.charCodeAt(i));
|
bytes.push(propKey.charCodeAt(i));
|
||||||
bytes.push(0);
|
bytes.push(0);
|
||||||
|
@ -74,9 +75,9 @@ export default class utils {
|
||||||
return searchableprops;
|
return searchableprops;
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* AllProperties- the resullsts from web.select("Title", "AllProperties").expand("AllProperties").get()
|
* AllProperties- the results from web.select("Title", "AllProperties").expand("AllProperties").get()
|
||||||
* propertiesToSelect- The properties you waant to select out of AllProperties
|
* propertiesToSelect- The properties you want to select out of AllProperties
|
||||||
* searchableProperties-- and araay of properties which are known to be searchjable
|
* searchableProperties-- and array of properties which are known to be searchable
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
/**
|
/**
|
||||||
|
@ -85,7 +86,7 @@ export default class utils {
|
||||||
* @static
|
* @static
|
||||||
* @param {*} AllProperties
|
* @param {*} AllProperties
|
||||||
* @param {Array<string>} propertiesToSelect The Properties to Select from AllProperties
|
* @param {Array<string>} propertiesToSelect The Properties to Select from AllProperties
|
||||||
* @param {Array<string>} searchableProperties An Array of Searchable Properties. These will be marked as seartchable in the results
|
* @param {Array<string>} searchableProperties An Array of Searchable Properties. These will be marked as searchable in the results
|
||||||
* @param {boolean} [addMissingProps] Indicates if the method should add a empty property if it is in propertiesToSelect but not in AllProperties
|
* @param {boolean} [addMissingProps] Indicates if the method should add a empty property if it is in propertiesToSelect but not in AllProperties
|
||||||
* @returns {Array<DisplayProp>}
|
* @returns {Array<DisplayProp>}
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,197 +0,0 @@
|
||||||
|
|
||||||
SPFX PROJECT UPGRADE
|
|
||||||
====================
|
|
||||||
|
|
||||||
Upgrades SharePoint Framework project to the specified version
|
|
||||||
|
|
||||||
|
|
||||||
USAGE
|
|
||||||
|
|
||||||
m365 spfx project upgrade [options]
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
OPTIONS
|
|
||||||
|
|
||||||
-v, --toVersion [toVersion]
|
|
||||||
The version of SharePoint Framework to which upgrade the project
|
|
||||||
|
|
||||||
--packageManager [packageManager]
|
|
||||||
The package manager you use. Supported managers npm,pnpm,yarn. Default npm
|
|
||||||
|
|
||||||
--shell [shell]
|
|
||||||
The shell you use. Supported shells bash,powershell,cmd. Default bash
|
|
||||||
|
|
||||||
--preview
|
|
||||||
Upgrade project to the latest SPFx preview version
|
|
||||||
|
|
||||||
-f, --outputFile [outputFile]
|
|
||||||
Path to the file where the upgrade report should be stored in. Ignored when output is tour
|
|
||||||
|
|
||||||
-h, --help [help]
|
|
||||||
Output usage information. Optionally, specify which section of command's help you want to see. Allowed values are options, examples, remarks, response, full. Default is full.
|
|
||||||
|
|
||||||
--query [query]
|
|
||||||
JMESPath query string. See http://jmespath.org/ for more information and examples
|
|
||||||
|
|
||||||
-o, --output [output]
|
|
||||||
Output type. json,text,csv,md. Default json
|
|
||||||
|
|
||||||
--verbose
|
|
||||||
Runs command with verbose logging
|
|
||||||
|
|
||||||
--debug
|
|
||||||
Runs command with debug logging
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
REMARKS
|
|
||||||
|
|
||||||
The spfx project upgrade command helps you upgrade your SharePoint Framework project to the specified version. If no version is specified, the command will upgrade to the latest version of the SharePoint Framework it supports (v1.17.2).
|
|
||||||
|
|
||||||
This command doesn't change your project files. Instead, it gives you a report with all steps necessary to upgrade your project to the specified version of the SharePoint Framework. Changing project files is error-prone, especially when it comes to updating your solution's code. This is why at this moment, this command produces a report that you can use yourself to perform the necessary updates and verify that everything is working as expected.
|
|
||||||
|
|
||||||
!!! important
|
|
||||||
Run this command in the folder where the project that you want to upgrade is located. This command doesn't change your project files.
|
|
||||||
|
|
||||||
|
|
||||||
EXAMPLES
|
|
||||||
|
|
||||||
Get instructions to upgrade the current SharePoint Framework project to SharePoint Framework version 1.5.0 and save the findings in a Markdown file
|
|
||||||
|
|
||||||
m365 spfx project upgrade --toVersion 1.5.0 --output md > "upgrade-report.md"
|
|
||||||
|
|
||||||
|
|
||||||
Get instructions to upgrade the current SharePoint Framework project to SharePoint Framework version 1.5.0 and show the summary of the findings in the shell
|
|
||||||
|
|
||||||
m365 spfx project upgrade --toVersion 1.5.0 --output text
|
|
||||||
|
|
||||||
|
|
||||||
Get instructions to upgrade the current SharePoint Framework project to the latest preview version
|
|
||||||
|
|
||||||
m365 spfx project upgrade --preview --output text
|
|
||||||
|
|
||||||
|
|
||||||
Get instructions to upgrade the current SharePoint Framework project to the specified preview version
|
|
||||||
|
|
||||||
m365 spfx project upgrade --toVersion 1.12.1-rc.0 --output text
|
|
||||||
|
|
||||||
|
|
||||||
Get instructions to upgrade the current SharePoint Framework project to the latest SharePoint Framework version supported by the CLI for Microsoft 365 using pnpm
|
|
||||||
|
|
||||||
m365 spfx project upgrade --packageManager pnpm --output text
|
|
||||||
|
|
||||||
|
|
||||||
Get instructions to upgrade the current SharePoint Framework project to the latest SharePoint Framework version supported by the CLI for Microsoft 365
|
|
||||||
|
|
||||||
m365 spfx project upgrade --output text
|
|
||||||
|
|
||||||
|
|
||||||
Get instructions to upgrade the current SharePoint Framework project to the latest SharePoint Framework version supported by the CLI for Microsoft 365 using PowerShell
|
|
||||||
|
|
||||||
m365 spfx project upgrade --shell powershell --output text
|
|
||||||
|
|
||||||
|
|
||||||
Get instructions to upgrade the current SharePoint Framework project to the latest version of SharePoint Framework and save the findings in a CodeTour (https://aka.ms/codetour) file
|
|
||||||
|
|
||||||
m365 spfx project upgrade --output tour
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
RESPONSE
|
|
||||||
|
|
||||||
When upgrading an SPFx project built using version 1.15.0 to SPFx version 1.15.2, you'll get output similar to following (output is truncated):
|
|
||||||
|
|
||||||
JSON
|
|
||||||
|
|
||||||
[
|
|
||||||
{
|
|
||||||
"description": "Upgrade SharePoint Framework dependency package @microsoft/sp-core-library",
|
|
||||||
"id": "FN001001",
|
|
||||||
"file": "./package.json",
|
|
||||||
"position": {
|
|
||||||
"line": 15,
|
|
||||||
"character": 5
|
|
||||||
},
|
|
||||||
"resolution": "npm i -SE @microsoft/sp-core-library@1.15.2",
|
|
||||||
"resolutionType": "cmd",
|
|
||||||
"severity": "Required",
|
|
||||||
"title": "@microsoft/sp-core-library"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"description": "Update version in .yo-rc.json",
|
|
||||||
"id": "FN010001",
|
|
||||||
"file": "./.yo-rc.json",
|
|
||||||
"position": {
|
|
||||||
"line": 5,
|
|
||||||
"character": 5
|
|
||||||
},
|
|
||||||
"resolution": "{\\\n \"@microsoft/generator-sharepoint\": {\\\n \"version\": \"1.15.2\"\\\n }\\\n}",
|
|
||||||
"resolutionType": "json",
|
|
||||||
"severity": "Recommended",
|
|
||||||
"title": ".yo-rc.json version"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
Text
|
|
||||||
|
|
||||||
Execute in bash
|
|
||||||
-----------------------
|
|
||||||
npm i -SE @microsoft/sp-core-library@1.15.2
|
|
||||||
|
|
||||||
./.yo-rc.json
|
|
||||||
-------------
|
|
||||||
Update version in .yo-rc.json:
|
|
||||||
{
|
|
||||||
"@microsoft/generator-sharepoint": {
|
|
||||||
"version": "1.15.2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Markdown
|
|
||||||
|
|
||||||
# Upgrade project HelloWorld to v1.15.2
|
|
||||||
|
|
||||||
Date: 20/11/2022
|
|
||||||
|
|
||||||
## Findings
|
|
||||||
|
|
||||||
Following is the list of steps required to upgrade your project to SharePoint Framework version 1.15.2. Summary of the modifications is included at the end of the report.
|
|
||||||
|
|
||||||
### FN001001 @microsoft/sp-core-library | Required
|
|
||||||
|
|
||||||
Upgrade SharePoint Framework dependency package @microsoft/sp-core-library
|
|
||||||
|
|
||||||
Execute the following command:
|
|
||||||
|
|
||||||
`sh
|
|
||||||
npm i -SE @microsoft/sp-core-library@1.15.2
|
|
||||||
|
|
||||||
|
|
||||||
File: ./package.json:17:5
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
### Execute script
|
|
||||||
|
|
||||||
`sh
|
|
||||||
npm i -SE @microsoft/sp-core-library@1.15.2
|
|
||||||
`
|
|
||||||
|
|
||||||
### Modify files
|
|
||||||
|
|
||||||
#### ./.yo-rc.json
|
|
||||||
|
|
||||||
Update version in .yo-rc.json:
|
|
||||||
|
|
||||||
`json
|
|
||||||
{
|
|
||||||
"@microsoft/generator-sharepoint": {
|
|
||||||
"version": "1.15.2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
|
|