Added theme support
This commit is contained in:
parent
e4e1a044b1
commit
a23babceac
|
@ -1,8 +1,12 @@
|
||||||
{
|
{
|
||||||
"@microsoft/generator-sharepoint": {
|
"@microsoft/generator-sharepoint": {
|
||||||
"version": "1.1.1",
|
"isDomainIsolated": false,
|
||||||
|
"isCreatingSolution": false,
|
||||||
|
"packageManager": "npm",
|
||||||
|
"version": "1.10.0",
|
||||||
"libraryName": "spsecurity-webpart-3",
|
"libraryName": "spsecurity-webpart-3",
|
||||||
"libraryId": "788271fb-ee9b-40df-8381-eb3dc70d1982",
|
"libraryId": "788271fb-ee9b-40df-8381-eb3dc70d1982",
|
||||||
"environment": "spo"
|
"environment": "spo",
|
||||||
|
"componentType": "webpart"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -13,25 +13,27 @@ extensions:
|
||||||
- react
|
- react
|
||||||
createdDate: 12/1/2017 12:00:00 AM
|
createdDate: 12/1/2017 12:00:00 AM
|
||||||
---
|
---
|
||||||
# SPFx React Grid
|
# SPFX React Grid
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
|
|
||||||
React-securitygrid is an SPFx webpart that uses React and Office-UI-Fabric to render a grid showing which users have access to which lists/libraries/folders/files on a Web as shown here:
|
React-securitygrid is an SPFX webpart that uses React and Office-UI-Fabric to render a grid showing which users have access to which lists/libraries/folders/files on a Web as shown here:
|
||||||
|
|
||||||
![config panel](./src/images/MainDisplay.PNG)
|
![config panel](./src/images/MainDisplay.gif)
|
||||||
|
|
||||||
Empty libraries are displayed with a black folder icon, those with items are displayed with a white folder. The user can expand a list or library by clicking on the desired row. For deeply nested folders the Title column can be resized by drag and drop. The display shows a 'filled-in' circle if the user has the selected permission to the given list, library, file or folder. (NOTE:The grid does not currently take into account access give via membership in an active directory group). The user must have permissions to access lists and enumerate permissions in order to view the grid.
|
Empty libraries are displayed with a black folder icon, those with items are displayed with a white folder. The user can expand a list or library by clicking on the desired row. (If the library or folder has more than 5000 items an error will be displayed ) For deeply nested folders the Title column can be resized by drag and drop. The display shows the appropriate icon circle if the user has the selected permission to the given list, library, file or folder. (NOTE:The grid does not currently take into account access give via membership in an active directory group-- coming soon!).
|
||||||
|
|
||||||
The user can change the permission being tested by clicking the Permission in the command bar and selecting a new Permission:
|
> IMPORTANT: The user must have permissions to access lists and enumerate permissions in order to view the grid.
|
||||||
|
|
||||||
|
The user can change the permission being tested by clicking the Permission in the command bar and selecting the new Permission:
|
||||||
|
|
||||||
![permission panel](./src/images/selectPermissionsPopout.PNG)
|
![permission panel](./src/images/selectPermissionsPopout.PNG)
|
||||||
|
|
||||||
The user can change which users are being shown in the grid by selecting the users button in the command bar and selecting a desired users:
|
The user can change which users are being shown in the grid by selecting the users button in the command bar and selecting the desired users:
|
||||||
|
|
||||||
![Select users](./src/images/SelectUsersPopout.PNG)
|
![Select users](./src/images/SelectUsersPopout.PNG)
|
||||||
|
|
||||||
The user can change which lists are being shown in the grid by selecting the lists button in the command bar and selecting a desired lists:
|
The user can change which lists are being shown in the grid by selecting the lists button in the command bar and selecting the desired lists:
|
||||||
|
|
||||||
![Select Lists](./src/images/Selectlistspopout.PNG)
|
![Select Lists](./src/images/Selectlistspopout.PNG)
|
||||||
|
|
||||||
|
@ -39,36 +41,45 @@ The user can change alternate between displaying user names and emails selectin
|
||||||
|
|
||||||
![Select Mode](./src/images/SelectDisplayModePopout.PNG)
|
![Select Mode](./src/images/SelectDisplayModePopout.PNG)
|
||||||
|
|
||||||
The the first configuration panel of the webpart is shown below:
|
The first configuration panel of the webpart is shown below:
|
||||||
|
|
||||||
![config panel](./src/images/Configuration.PNG)
|
![config panel](./src/images/Configuration.PNG)
|
||||||
|
|
||||||
Permission Settings
|
### Permission Settings
|
||||||
|
|
||||||
The Permission Type dropdown sets the default permission to check.The 'Let user select Permission' checkbox determines whether the user can change this permission.
|
The Permission Settings allow you to select which permissions to show in the grid and to select the Icon and color used to display the selected permission.
|
||||||
|
|
||||||
User Settings
|
### User Settings
|
||||||
|
|
||||||
The Show Email or Name Toggle determines whether the name or email is displayed by default.
|
The Show Email or Name Toggle determines whether the name or email is displayed by default.
|
||||||
|
|
||||||
The Show Security Groups checkbox determines whether SharePoint Security groups are included in the grid.
|
The Show Security Groups checkbox determines whether SharePoint Security groups are included in the grid.
|
||||||
|
|
||||||
The Show Users checkbox determines whether Users are included in the grid.
|
The Show Users checkbox determines whether Users are included in the grid.
|
||||||
|
|
||||||
|
The Only show users with permissions toggle determines whether the grid should display all users with access to the web, or only users with the selected permission
|
||||||
|
![config panel](./src/images/Permissions.gif)
|
||||||
|
|
||||||
The Let Users Select users checkbox determines whether Users can filter the selected users in the grid.
|
The Let Users Select users checkbox determines whether Users can filter the selected users in the grid.
|
||||||
|
|
||||||
Display Settings
|
### Display Settings
|
||||||
|
|
||||||
The Initial Title column width determines the initial width of the Title column(it can be resized).
|
The Initial Title column width determines the initial width of the Title column(it can be resized).
|
||||||
|
|
||||||
The second configuration panel allows the owner to configure the List Settings
|
The second configuration panel allows the owner to configure the List Settings
|
||||||
![List Configuration panel](./src/images/ListConfiguration.PNG)
|
![List Configuration panel](./src/images/ListConfiguration.PNG)
|
||||||
|
|
||||||
List Settings
|
### List Settings
|
||||||
|
|
||||||
The Show Hidden Lists checkbox determines whether Hidden lists are displayed.
|
The Show Hidden Lists checkbox determines whether Hidden lists are displayed.
|
||||||
|
|
||||||
The Show System Lists checkbox determines whether System Lists (Catalogs) are included in the grid.
|
The Show System Lists checkbox determines whether System Lists (Catalogs) are included in the grid.
|
||||||
|
|
||||||
The Show Users checkbox determines whether Users are included in the grid.
|
The Show Users checkbox determines whether Users are included in the grid.
|
||||||
|
|
||||||
The Let Users Select lists checkbox determines whether Users can filter the selected lists in the grid.
|
The Let Users Select lists checkbox determines whether Users can filter the selected lists in the grid.
|
||||||
|
|
||||||
Select Lists
|
### Select Lists
|
||||||
|
|
||||||
The Include/Exclude Selected lists Toggle determines whether the lists selected are to be included or excluded.
|
The Include/Exclude Selected lists Toggle determines whether the lists selected are to be included or excluded.
|
||||||
|
|
||||||
|
@ -80,7 +91,7 @@ This is a port of an Angular 1.3 SharePoint hosted App at https://github.com/rus
|
||||||
|
|
||||||
## Used SharePoint Framework Version
|
## Used SharePoint Framework Version
|
||||||
|
|
||||||
![version](https://img.shields.io/badge/version-1.4.1-green.svg)
|
![version](https://img.shields.io/badge/version-1.10-green.svg)
|
||||||
|
|
||||||
## Applies to
|
## Applies to
|
||||||
|
|
||||||
|
@ -101,6 +112,7 @@ Solution|Author(s)
|
||||||
|
|
||||||
Version|Date|Comments
|
Version|Date|Comments
|
||||||
-------|----|--------
|
-------|----|--------
|
||||||
|
1.0.0.2|April 5, 2021| Updates to SPFx 1.10; Allow display of multiple permissions
|
||||||
1.0.0.1|April 25, 2018|Update to SPFx 1.4.1
|
1.0.0.1|April 25, 2018|Update to SPFx 1.4.1
|
||||||
1.0.0.0|December 31, 2016|Initial version
|
1.0.0.0|December 31, 2016|Initial version
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://dev.office.com/json-schemas/spfx-build/config.2.0.schema.json",
|
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
|
||||||
"version": "2.0",
|
"version": "2.0",
|
||||||
"bundles": {
|
"bundles": {
|
||||||
"sp-security-bundle": {
|
"sp-security-bundle": {
|
||||||
|
@ -16,4 +16,4 @@
|
||||||
"PropertyControlStrings": "./node_modules/@pnp/spfx-property-controls/lib/loc/{locale}.js"
|
"PropertyControlStrings": "./node_modules/@pnp/spfx-property-controls/lib/loc/{locale}.js"
|
||||||
},
|
},
|
||||||
"externals": {}
|
"externals": {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://dev.office.com/json-schemas/spfx-build/copy-assets.schema.json",
|
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json",
|
||||||
"deployCdnPath": "temp/deploy"
|
"deployCdnPath": "temp/deploy"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://dev.office.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
|
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
|
||||||
"workingDir": "./temp/deploy/",
|
"workingDir": "./temp/deploy/",
|
||||||
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
||||||
"container": "spsecurity-webpart-3",
|
"container": "spsecurity-webpart-3",
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
|
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
|
||||||
"solution": {
|
"solution": {
|
||||||
|
"includeClientSideAssets": true,
|
||||||
|
"isDomainIsolated": false,
|
||||||
"name": "spsecurity-webpart-3-client-side-solution",
|
"name": "spsecurity-webpart-3-client-side-solution",
|
||||||
"id": "788271fb-ee9b-40df-8381-eb3dc70d1982",
|
"id": "788271fb-ee9b-40df-8381-eb3dc70d1982",
|
||||||
"version": "1.0.0.1"
|
"version": "1.0.0.1"
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://dev.office.com/json-schemas/core-build/serve.schema.json",
|
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
|
||||||
"port": 4321,
|
"port": 4321,
|
||||||
"initialPage": "https://localhost:5432/workbench",
|
"initialPage": "https://localhost:5432/workbench",
|
||||||
"https": true,
|
"https": true,
|
||||||
"api": {
|
"api": {
|
||||||
"port": 5432,
|
"port": 5432,
|
||||||
"entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/"
|
"entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/"
|
||||||
|
},
|
||||||
|
"serveConfigurations": {
|
||||||
|
"default": {
|
||||||
|
"pageUrl": "https://russellwgove.sharepoint.com/sites/workspaces/_layouts/15/workbench.aspx"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,45 +0,0 @@
|
||||||
{
|
|
||||||
"$schema": "https://dev.office.com/json-schemas/core-build/tslint.schema.json",
|
|
||||||
// Display errors as warnings
|
|
||||||
"displayAsWarning": true,
|
|
||||||
// The TSLint task may have been configured with several custom lint rules
|
|
||||||
// before this config file is read (for example lint rules from the tslint-microsoft-contrib
|
|
||||||
// project). If true, this flag will deactivate any of these rules.
|
|
||||||
"removeExistingRules": true,
|
|
||||||
// When true, the TSLint task is configured with some default TSLint "rules.":
|
|
||||||
"useDefaultConfigAsBase": false,
|
|
||||||
// Since removeExistingRules=true and useDefaultConfigAsBase=false, there will be no lint rules
|
|
||||||
// which are active, other than the list of rules below.
|
|
||||||
"lintConfig": {
|
|
||||||
// Opt-in to Lint rules which help to eliminate bugs in JavaScript
|
|
||||||
"rules": {
|
|
||||||
"class-name": false,
|
|
||||||
"export-name": false,
|
|
||||||
"forin": false,
|
|
||||||
"label-position": false,
|
|
||||||
"member-access": true,
|
|
||||||
"no-arg": false,
|
|
||||||
"no-console": false,
|
|
||||||
"no-construct": false,
|
|
||||||
"no-duplicate-case": true,
|
|
||||||
"no-duplicate-variable": true,
|
|
||||||
"no-eval": false,
|
|
||||||
"no-function-expression": true,
|
|
||||||
"no-internal-module": true,
|
|
||||||
"no-shadowed-variable": true,
|
|
||||||
"no-switch-case-fall-through": true,
|
|
||||||
"no-unnecessary-semicolons": true,
|
|
||||||
"no-unused-expression": true,
|
|
||||||
"no-use-before-declare": true,
|
|
||||||
"no-with-statement": true,
|
|
||||||
"semicolon": true,
|
|
||||||
"trailing-comma": false,
|
|
||||||
"typedef": false,
|
|
||||||
"typedef-whitespace": false,
|
|
||||||
"use-named-parameter": true,
|
|
||||||
"valid-typeof": true,
|
|
||||||
"variable-name": false,
|
|
||||||
"whitespace": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"$schema": "https://dev.office.com/json-schemas/spfx-build/write-manifests.schema.json",
|
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/write-manifests.schema.json",
|
||||||
"cdnBasePath": "<!-- PATH TO CDN -->"
|
"cdnBasePath": "<!-- PATH TO CDN -->"
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,4 +7,5 @@ build.addSuppression(`Warning - [sass] The local CSS class 'ms-DetailsHeader' is
|
||||||
build.addSuppression(`Warning - [sass] The local CSS class 'ms-DetailsHeader-cell' is not camelCase and will not be type-safe.`);
|
build.addSuppression(`Warning - [sass] The local CSS class 'ms-DetailsHeader-cell' is not camelCase and will not be type-safe.`);
|
||||||
build.addSuppression(`Warning - [sass] The local CSS class 'ms-List-cell' is not camelCase and will not be type-safe.`);
|
build.addSuppression(`Warning - [sass] The local CSS class 'ms-List-cell' is not camelCase and will not be type-safe.`);
|
||||||
build.addSuppression(`Warning - [sass] The local CSS class 'ms-DetailsRow' is not camelCase and will not be type-safe.`);
|
build.addSuppression(`Warning - [sass] The local CSS class 'ms-DetailsRow' is not camelCase and will not be type-safe.`);
|
||||||
|
|
||||||
build.initialize(gulp);
|
build.initialize(gulp);
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,39 +1,49 @@
|
||||||
{
|
{
|
||||||
|
"main": "lib/index.js",
|
||||||
"name": "spsecurity-webpart-3",
|
"name": "spsecurity-webpart-3",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"private": true,
|
"private": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
},
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"@types/react": "16.8.8"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@microsoft/sp-build-web": "~1.4.1",
|
|
||||||
"@microsoft/sp-core-library": "~1.4.1",
|
|
||||||
"@microsoft/sp-module-interfaces": "~1.4.1",
|
|
||||||
"@microsoft/sp-webpart-base": "~1.4.1",
|
|
||||||
"@microsoft/sp-webpart-workbench": "~1.4.1",
|
|
||||||
"@pnp/common": "1.3.3",
|
"@pnp/common": "1.3.3",
|
||||||
"@pnp/logging": "1.3.3",
|
"@pnp/logging": "1.3.3",
|
||||||
"@pnp/odata": "1.3.3",
|
"@pnp/odata": "1.3.3",
|
||||||
"@pnp/sp": "1.3.3",
|
"@pnp/sp": "1.3.3",
|
||||||
"@pnp/spfx-property-controls": "1.0.0",
|
"@pnp/spfx-property-controls": "1.0.0",
|
||||||
"@types/react": "15.0.38",
|
"@types/es6-promise": "0.0.33",
|
||||||
"@types/react-addons-shallow-compare": "0.14.17",
|
"@types/react": "16.8.8",
|
||||||
"@types/react-addons-test-utils": "0.14.15",
|
"@types/react-dom": "16.8.3",
|
||||||
"@types/react-addons-update": "0.14.14",
|
"@types/webpack-env": "1.13.1",
|
||||||
"@types/react-dom": "0.14.18",
|
"lodash": "^4.17.4",
|
||||||
"@types/webpack-env": ">=1.12.1 <1.14.0",
|
"natives": "^1.1.6",
|
||||||
"lodash": "^4.17.15",
|
"office-ui-fabric-react": "6.189.2",
|
||||||
"office-ui-fabric-react": "^4.21.2",
|
"react": "16.8.5",
|
||||||
"react": "15.4.2",
|
"react-dom": "16.8.5"
|
||||||
"react-dom": "15.4.2"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@microsoft/sp-build-web": "~1.4.1",
|
"@microsoft/rush-stack-compiler-3.2": "0.6.8",
|
||||||
"@microsoft/sp-module-interfaces": "~1.4.1",
|
"@microsoft/rush-stack-compiler-3.3": "0.3.5",
|
||||||
"@microsoft/sp-webpart-workbench": "~1.4.1",
|
"@microsoft/sp-build-web": "1.10.0",
|
||||||
"@types/chai": ">=3.4.34 <3.6.0",
|
"@microsoft/sp-core-library": "1.10.0",
|
||||||
"@types/mocha": ">=2.2.33 <2.6.0",
|
"@microsoft/sp-lodash-subset": "1.10.0",
|
||||||
"gulp": "~3.9.1"
|
"@microsoft/sp-module-interfaces": "1.10.0",
|
||||||
|
"@microsoft/sp-office-ui-fabric-core": "1.10.0",
|
||||||
|
"@microsoft/sp-property-pane": "1.10.0",
|
||||||
|
"@microsoft/sp-tslint-rules": "1.10.0",
|
||||||
|
"@microsoft/sp-webpart-base": "1.10.0",
|
||||||
|
"@microsoft/sp-webpart-workbench": "1.10.0",
|
||||||
|
"@types/chai": "3.4.34",
|
||||||
|
"@types/mocha": "2.2.38",
|
||||||
|
"ajv": "~5.2.2",
|
||||||
|
"gulp": "~3.9.1",
|
||||||
|
"i": "0.3.6",
|
||||||
|
"npm": "6.14.4",
|
||||||
|
"tslint-microsoft-contrib": "5.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "gulp bundle",
|
"build": "gulp bundle",
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 206 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.0 MiB |
|
@ -0,0 +1 @@
|
||||||
|
// A file is required to be in the root of the /src directory by the TypeScript compiler
|
|
@ -1,49 +0,0 @@
|
||||||
{
|
|
||||||
// Display errors as warnings
|
|
||||||
"displayAsWarning": true,
|
|
||||||
// The TSLint task may have been configured with several custom lint rules
|
|
||||||
// before this config file is read (for example lint rules from the tslint-microsoft-contrib
|
|
||||||
// project). If true, this flag will deactivate any of these rules.
|
|
||||||
"removeExistingRules": true,
|
|
||||||
// When true, the TSLint task is configured with some default TSLint "rules.":
|
|
||||||
"useDefaultConfigAsBase": false,
|
|
||||||
// Since removeExistingRules=true and useDefaultConfigAsBase=false, there will be no lint rules
|
|
||||||
// which are active, other than the list of rules below.
|
|
||||||
"lintConfig": {
|
|
||||||
// Opt-in to Lint rules which help to eliminate bugs in JavaScript
|
|
||||||
"rules": {
|
|
||||||
"class-name": false,
|
|
||||||
"export-name": false,
|
|
||||||
"forin": false,
|
|
||||||
"label-position": false,
|
|
||||||
"member-access": true,
|
|
||||||
"no-arg": false,
|
|
||||||
"no-console": false,
|
|
||||||
"no-construct": false,
|
|
||||||
"no-duplicate-case": true,
|
|
||||||
"no-duplicate-variable": true,
|
|
||||||
"no-eval": false,
|
|
||||||
"no-function-expression": true,
|
|
||||||
"no-internal-module": true,
|
|
||||||
"no-shadowed-variable": true,
|
|
||||||
"no-switch-case-fall-through": true,
|
|
||||||
"no-unnecessary-semicolons": true,
|
|
||||||
"no-unused-expression": false,
|
|
||||||
"no-unused-imports": true,
|
|
||||||
"no-use-before-declare": true,
|
|
||||||
"no-with-statement": true,
|
|
||||||
"semicolon": true,
|
|
||||||
"trailing-comma": false,
|
|
||||||
"typedef": false,
|
|
||||||
"typedef-whitespace": false,
|
|
||||||
"use-named-parameter": true,
|
|
||||||
"valid-typeof": true,
|
|
||||||
"variable-name": false,
|
|
||||||
"whitespace": false,
|
|
||||||
|
|
||||||
"no-debugger":false,
|
|
||||||
"no-unused-variable": false,
|
|
||||||
"max-line-lenth": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {sp} from "@pnp/sp";
|
import { sp } from "@pnp/sp";
|
||||||
import { find, indexOf, includes } from "lodash";
|
import { find, indexOf, includes } from "lodash";
|
||||||
import { SPPermission } from "@microsoft/sp-page-context";
|
import { SPPermission } from "@microsoft/sp-page-context";
|
||||||
import { GraphHttpClient, HttpClientResponse, IGraphHttpClientOptions } from "@microsoft/sp-http";
|
import { AadHttpClient, HttpClientResponse, IAadHttpClientOptions } from "@microsoft/sp-http";
|
||||||
|
|
||||||
export interface ISPSecurableObject {
|
export interface ISPSecurableObject {
|
||||||
id: number;
|
id: number;
|
||||||
|
@ -69,6 +69,7 @@ export class SPSecurityInfo {
|
||||||
this.siteUsers = new Array<SPSiteUser>();
|
this.siteUsers = new Array<SPSiteUser>();
|
||||||
this.lists = new Array<SPList>();
|
this.lists = new Array<SPList>();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +111,20 @@ export class SPRoleAssignment {
|
||||||
|
|
||||||
}
|
}
|
||||||
export class Helpers {
|
export class Helpers {
|
||||||
|
public static doesUserHaveAnyPermission(securableObjects: any[], user, requestedpermissions: SPPermission[], roles, siteGroups): boolean {
|
||||||
|
for (var securableObject of securableObjects) {
|
||||||
|
for (var requestedpermission of requestedpermissions) {
|
||||||
|
if (Helpers.doesUserHavePermission(securableObject, user, requestedpermission, roles, siteGroups)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
public static doesUserHavePermission(securableObject, user, requestedpermission: SPPermission, roles, siteGroups) {
|
public static doesUserHavePermission(securableObject, user, requestedpermission: SPPermission, roles, siteGroups) {
|
||||||
|
console.log(`check user ${user.name} obj ${securableObject.title} perm ${requestedpermission.value.High}${requestedpermission.value.Low} `);
|
||||||
|
|
||||||
|
|
||||||
const permissions: SPBasePermissions[] = Helpers.getUserPermissionsForObject(securableObject, user, roles, siteGroups);
|
const permissions: SPBasePermissions[] = Helpers.getUserPermissionsForObject(securableObject, user, roles, siteGroups);
|
||||||
for (const permission of permissions) {
|
for (const permission of permissions) {
|
||||||
if (
|
if (
|
||||||
|
@ -193,7 +207,7 @@ export class Helpers {
|
||||||
}
|
}
|
||||||
return selectedRoleAssignments;
|
return selectedRoleAssignments;
|
||||||
} catch (exception) {
|
} catch (exception) {
|
||||||
debugger;
|
//debugger;
|
||||||
console.error(exception);
|
console.error(exception);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -262,7 +276,7 @@ export default class SPSecurityService {
|
||||||
for (let roleAssignmentObject of listItem.RoleAssignments) {
|
for (let roleAssignmentObject of listItem.RoleAssignments) {
|
||||||
|
|
||||||
let roleAssignment: SPRoleAssignment = {
|
let roleAssignment: SPRoleAssignment = {
|
||||||
roleDefinitionIds: roleAssignmentObject.RoleDefinitionBindings.map((rdb) => { return rdb.Id; }),
|
roleDefinitionIds: roleAssignmentObject.RoleDefinitionBindings.map((rdb) => { return rdb.Id; }),
|
||||||
principalId: roleAssignmentObject.PrincipalId
|
principalId: roleAssignmentObject.PrincipalId
|
||||||
};
|
};
|
||||||
// if (roleAssignmentObject.Member.UserId) {
|
// if (roleAssignmentObject.Member.UserId) {
|
||||||
|
@ -291,26 +305,27 @@ export default class SPSecurityService {
|
||||||
return itemsToAdd;
|
return itemsToAdd;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public async getMembersOfAdGroup(graphHttpClient: GraphHttpClient, groupName: string): Promise<any> {
|
// public async getMembersOfAdGroup(aadHttpClient: AadHttpClient, groupName: string): Promise<any> {
|
||||||
|
|
||||||
return graphHttpClient.get("v1.0/groups?$filter=displayName eq '" + groupName + "'&$expand=members",
|
// return aadHttpClient.get("v1.0/groups?$filter=displayName eq '" + groupName + "'&$expand=members",
|
||||||
GraphHttpClient.configurations.v1).then((response) => {
|
// AadHttpClient.configurations.v1).then((response) => {
|
||||||
response.json().then((data) => {
|
// response.json().then((data) => {
|
||||||
debugger;
|
// debugger;
|
||||||
});
|
// });
|
||||||
}).catch((err) => {
|
// }).catch((err) => {
|
||||||
});
|
// console.log(err);
|
||||||
}
|
// });
|
||||||
|
// }
|
||||||
/// Loads data for intial display
|
/// Loads data for intial display
|
||||||
public loadData(showHiddenLists: boolean, showCatalogs: boolean, graphHttpClient: GraphHttpClient, forceReload: boolean): Promise<SPSecurityInfo> {
|
public loadData(showHiddenLists: boolean, showCatalogs: boolean, aadHttpClient: AadHttpClient, forceReload: boolean): Promise<SPSecurityInfo> {
|
||||||
let securityInfo: SPSecurityInfo = new SPSecurityInfo();
|
let securityInfo: SPSecurityInfo = new SPSecurityInfo();
|
||||||
let batch: any = sp.createBatch();
|
let batch: any = sp.createBatch();
|
||||||
|
let errors: Array<string> = [];
|
||||||
|
|
||||||
sp.web.siteUsers
|
sp.web.siteUsers.inBatch(batch).get()
|
||||||
.inBatch(batch).get().then((response) => {
|
.then((response) => {
|
||||||
console.table(response);
|
console.table(response);
|
||||||
securityInfo.siteUsers = response.map((u) => {
|
securityInfo.siteUsers = response.map((u) => {
|
||||||
|
|
||||||
let user: SPSiteUser = new SPSiteUser();
|
let user: SPSiteUser = new SPSiteUser();
|
||||||
user.isSelected = true;
|
user.isSelected = true;
|
||||||
user.id = u.Id;
|
user.id = u.Id;
|
||||||
|
@ -325,9 +340,14 @@ export default class SPSecurityService {
|
||||||
return user;
|
return user;
|
||||||
});
|
});
|
||||||
return securityInfo.siteUsers;
|
return securityInfo.siteUsers;
|
||||||
|
}).catch((error) => {
|
||||||
|
debugger;
|
||||||
|
errors.push(`There was an error feting site users -- ${error.message}`);
|
||||||
|
throw error;
|
||||||
});
|
});
|
||||||
sp.web.siteGroups.expand("Users").select("Title", "Id", "IsHiddenInUI", "IsShareByEmailGuestUse", "IsSiteAdmin", "IsSiteAdmin")
|
sp.web.siteGroups.filter(`Title ne 'Limited Access System Group'`).expand("Users").select("Title", "Id", "IsHiddenInUI", "IsShareByEmailGuestUse", "IsSiteAdmin", "IsSiteAdmin")
|
||||||
.inBatch(batch).get().then((response) => {
|
.inBatch(batch).get()
|
||||||
|
.then((response) => {
|
||||||
let AdGroupPromises: Array<Promise<any>> = [];
|
let AdGroupPromises: Array<Promise<any>> = [];
|
||||||
// if group contains an ad group(PrincipalType=4) expand it
|
// if group contains an ad group(PrincipalType=4) expand it
|
||||||
securityInfo.siteGroups = response.map((grp) => {
|
securityInfo.siteGroups = response.map((grp) => {
|
||||||
|
@ -365,23 +385,33 @@ export default class SPSecurityService {
|
||||||
return securityInfo.siteGroups;
|
return securityInfo.siteGroups;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
}).catch((error) => {
|
||||||
|
//error fetching groups
|
||||||
|
errors.push(`There was an error feting site Groups -- ${error.message}`);
|
||||||
|
//debugger;
|
||||||
|
throw error;
|
||||||
});
|
});
|
||||||
sp.web.roleDefinitions.expand("BasePermissions").inBatch(batch).get().then((response) => {
|
sp.web.roleDefinitions.expand("BasePermissions").inBatch(batch).get()
|
||||||
securityInfo.roleDefinitions = response.map((rd) => {
|
.then((response) => {
|
||||||
|
securityInfo.roleDefinitions = response.map((rd) => {
|
||||||
|
|
||||||
const bp: SPBasePermissions = new SPBasePermissions(rd.BasePermissions.High, rd.BasePermissions.Low);
|
const bp: SPBasePermissions = new SPBasePermissions(rd.BasePermissions.High, rd.BasePermissions.Low);
|
||||||
const roleDefinition: SPRoleDefinition = new SPRoleDefinition(
|
const roleDefinition: SPRoleDefinition = new SPRoleDefinition(
|
||||||
parseInt(rd.Id, 10),
|
parseInt(rd.Id, 10),
|
||||||
bp,
|
bp,
|
||||||
rd.Description,
|
rd.Description,
|
||||||
rd.Hidden,
|
rd.Hidden,
|
||||||
rd.Name);
|
rd.Name);
|
||||||
|
|
||||||
return roleDefinition;
|
return roleDefinition;
|
||||||
|
});
|
||||||
|
return securityInfo.roleDefinitions;
|
||||||
|
}).catch((error) => {
|
||||||
|
//debugger;
|
||||||
|
//error fetching roledefinitions
|
||||||
|
errors.push(`There was an error fetcing role Definitions -- ${error.message}`);
|
||||||
|
throw error;
|
||||||
});
|
});
|
||||||
|
|
||||||
return securityInfo.roleDefinitions;
|
|
||||||
});
|
|
||||||
let filters: string[] = [];
|
let filters: string[] = [];
|
||||||
if (!showHiddenLists) {
|
if (!showHiddenLists) {
|
||||||
filters.push("Hidden eq false");
|
filters.push("Hidden eq false");
|
||||||
|
@ -392,10 +422,9 @@ export default class SPSecurityService {
|
||||||
let filter: string = filters.join(" and ");
|
let filter: string = filters.join(" and ");
|
||||||
sp.web.lists
|
sp.web.lists
|
||||||
.expand("RootFolder", "RoleAssignments", "RoleAssignments/RoleDefinitionBindings", "RoleAssignments/Member",
|
.expand("RootFolder", "RoleAssignments", "RoleAssignments/RoleDefinitionBindings", "RoleAssignments/Member",
|
||||||
"RoleAssignments/Member/Users", "RoleAssignments/Member/Groups", "RoleAssignments/Member/UserId")
|
"RoleAssignments/Member/Users", "RoleAssignments/Member/Groups", "RoleAssignments/Member/UserId")
|
||||||
.filter(filter)
|
.filter(filter).inBatch(batch).get()
|
||||||
.inBatch(batch).get().then((response) => {
|
.then((response) => {
|
||||||
|
|
||||||
securityInfo.lists = response.map((listObject) => {
|
securityInfo.lists = response.map((listObject) => {
|
||||||
let mylist: SPList = new SPList();
|
let mylist: SPList = new SPList();
|
||||||
mylist.isSelected = true;// Shoudl be shown in the UI, user can deslect it in the ui
|
mylist.isSelected = true;// Shoudl be shown in the UI, user can deslect it in the ui
|
||||||
|
@ -418,9 +447,20 @@ export default class SPSecurityService {
|
||||||
return mylist;
|
return mylist;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
}).catch((error) => {
|
||||||
|
//debugger;
|
||||||
|
errors.push(`There was an error fetching lists -- ${error.message} `);
|
||||||
|
//error fetching lists
|
||||||
|
throw error;
|
||||||
|
|
||||||
});
|
});
|
||||||
return batch.execute().then(() => {
|
return batch.execute().then(() => {
|
||||||
return securityInfo;
|
return securityInfo;
|
||||||
|
}).catch((error) => {
|
||||||
|
//debugger;
|
||||||
|
// error in batch
|
||||||
|
throw errors;
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,29 @@
|
||||||
import { SPSiteUser } from "../SPSecurityService";
|
import { SPSiteUser } from "../SPSecurityService";
|
||||||
import { SPPermission } from "@microsoft/sp-page-context";
|
export interface ISelectedPermission {
|
||||||
|
permission: string;
|
||||||
|
color: string;
|
||||||
|
iconName:string;
|
||||||
|
freindlyName:string;
|
||||||
|
isChecked?:boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface ISpSecurityWebPartProps {
|
export interface ISpSecurityWebPartProps {
|
||||||
users: SPSiteUser[];
|
users: SPSiteUser[];
|
||||||
permission: string;
|
//permission: string; // used if only one permission selected.... gonzo, all new now
|
||||||
|
selectedPermissions: ISelectedPermission[];// used if multiple permissions selected
|
||||||
showHiddenLists: boolean;
|
showHiddenLists: boolean;
|
||||||
showCatalogs:boolean;
|
showCatalogs: boolean;
|
||||||
letUserSelectPermission:boolean;
|
letUserSelectPermission: boolean;
|
||||||
letUserSelectUsers:boolean;
|
letUserSelectUsers: boolean;
|
||||||
letUserSelectLists:boolean;
|
letUserSelectLists: boolean;
|
||||||
includeAdminSelectedLists:boolean; // true to inlude them, false to excluder
|
includeAdminSelectedLists: boolean; // true to inlude them, false to excluder
|
||||||
adminSelectedLists:string[];
|
adminSelectedLists: string[];
|
||||||
listTitleColumnWidth:number;
|
listTitleColumnWidth: number;
|
||||||
showEmail:boolean; //0 show name, 1 show email
|
showEmail: boolean; //0 show name, 1 show email
|
||||||
showSecurityGroups:boolean; // show PrincipalType=4
|
showSecurityGroups: boolean; // show PrincipalType=4
|
||||||
showUsers:boolean; // show PrincipalType=1
|
showUsers: boolean; // show PrincipalType=1
|
||||||
|
showOnlyUsersWithPermission;// toggle to show everyone, or justy the users who have the permissions
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
{
|
{
|
||||||
"$schema": "../../../node_modules/@microsoft/sp-module-interfaces/lib/manifestSchemas/jsonSchemas/clientSideComponentManifestSchema.json",
|
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
|
||||||
"id": "41e37f03-2ea8-4f19-b77a-f2121a1e7c45",
|
"id": "41e37f03-2ea8-4f19-b77a-f2121a1e7c45",
|
||||||
"alias": "SpSecurityWebPart",
|
"alias": "SpSecurityWebPart",
|
||||||
"componentType": "WebPart",
|
"componentType": "WebPart",
|
||||||
|
@ -8,13 +8,17 @@
|
||||||
/**
|
/**
|
||||||
* This property should only be set to true if it is certain that the webpart does not
|
* This property should only be set to true if it is certain that the webpart does not
|
||||||
* allow arbitrary scripts to be called
|
* allow arbitrary scripts to be called
|
||||||
*/
|
*
|
||||||
"safeWithCustomScriptDisabled": false,
|
"requiresCustomScript": true,
|
||||||
|
*/
|
||||||
|
"supportedHosts": [
|
||||||
|
"SharePointWebPart"
|
||||||
|
],
|
||||||
"preconfiguredEntries": [
|
"preconfiguredEntries": [
|
||||||
{
|
{
|
||||||
"groupId": "41e37f03-2ea8-4f19-b77a-f2121a1e7c45",
|
"groupId": "41e37f03-2ea8-4f19-b77a-f2121a1e7c45",
|
||||||
"group": {
|
"group": {
|
||||||
"default": "Under Development"
|
"default": "Other"
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"default": "SPSecurity"
|
"default": "SPSecurity"
|
||||||
|
@ -33,7 +37,29 @@
|
||||||
"includeAdminSelectedLists": false,
|
"includeAdminSelectedLists": false,
|
||||||
"listTitleColumnWidth": 120,
|
"listTitleColumnWidth": 120,
|
||||||
"showEmail": false,
|
"showEmail": false,
|
||||||
"showUsers": true
|
"showUsers": true,
|
||||||
|
"showOnlyUsersWithPermission": true,
|
||||||
|
"selectedPermissions": [
|
||||||
|
{
|
||||||
|
"permission": "manageLists",
|
||||||
|
"color": "#0000FF",
|
||||||
|
"iconName": "Settings",
|
||||||
|
"freindlyName": "Manage"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"permission": "editListItems",
|
||||||
|
"color": "#FF0000",
|
||||||
|
"iconName": "Edit",
|
||||||
|
"freindlyName": "Edit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"permission": "viewListItems",
|
||||||
|
"color": "#00FF00",
|
||||||
|
"iconName": "View",
|
||||||
|
"freindlyName": "View"
|
||||||
|
}
|
||||||
|
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
@ -3,22 +3,19 @@ import * as ReactDom from "react-dom";
|
||||||
import { Version } from "@microsoft/sp-core-library";
|
import { Version } from "@microsoft/sp-core-library";
|
||||||
import { SPPermission } from "@microsoft/sp-page-context";
|
import { SPPermission } from "@microsoft/sp-page-context";
|
||||||
import { PropertyFieldListPicker, PropertyFieldListPickerOrderBy } from '@pnp/spfx-property-controls/lib/PropertyFieldListPicker';
|
import { PropertyFieldListPicker, PropertyFieldListPickerOrderBy } from '@pnp/spfx-property-controls/lib/PropertyFieldListPicker';
|
||||||
import {
|
import { PropertyFieldSelectedPermissions, IPropertyFieldSelectedPermissionsProps } from "./containers/PropertyFieldSelectedPermissions";
|
||||||
BaseClientSideWebPart,
|
import { sp } from "@pnp/sp";
|
||||||
IPropertyPaneConfiguration,
|
|
||||||
PropertyPaneTextField,
|
|
||||||
PropertyPaneDropdown, IPropertyPaneDropdownOption,
|
|
||||||
PropertyPaneCheckbox,
|
|
||||||
PropertyPaneToggle
|
|
||||||
} from "@microsoft/sp-webpart-base";
|
|
||||||
import {sp} from "@pnp/sp";
|
|
||||||
import * as strings from "spSecurityStrings";
|
import * as strings from "spSecurityStrings";
|
||||||
import SpSecurity from "./components/SpSecurity";
|
import SpSecurity from "./components/SpSecurity";
|
||||||
import { ISpSecurityProps } from "./components/ISpSecurityProps";
|
import { ISpSecurityProps } from "./components/ISpSecurityProps";
|
||||||
|
|
||||||
import { ISpSecurityWebPartProps } from "./ISpSecurityWebPartProps";
|
import { ISpSecurityWebPartProps } from "./ISpSecurityWebPartProps";
|
||||||
import { PropertyPaneSlider } from "@microsoft/sp-webpart-base/lib/propertyPane/propertyPaneFields/propertyPaneSlider/PropertyPaneSlider";
|
import { BaseClientSideWebPart } from "@microsoft/sp-webpart-base";
|
||||||
import PropertyPane from "@microsoft/sp-webpart-base/lib/propertyPane/propertyPane/PropertyPane";
|
import {
|
||||||
|
IPropertyPaneConfiguration, PropertyPaneCheckbox,
|
||||||
|
IPropertyPaneDropdownOption, PropertyPaneDropdown, PropertyPaneTextField,
|
||||||
|
PropertyPaneToggle, PropertyPaneSlider
|
||||||
|
} from "@microsoft/sp-property-pane";
|
||||||
|
|
||||||
export default class SpSecurityWebPart extends BaseClientSideWebPart<ISpSecurityWebPartProps> {
|
export default class SpSecurityWebPart extends BaseClientSideWebPart<ISpSecurityWebPartProps> {
|
||||||
public onInit(): Promise<void> {
|
public onInit(): Promise<void> {
|
||||||
|
@ -31,15 +28,18 @@ export default class SpSecurityWebPart extends BaseClientSideWebPart<ISpSecurity
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(): void {
|
public render(): void {
|
||||||
|
|
||||||
const props: ISpSecurityProps = {
|
const props: ISpSecurityProps = {
|
||||||
permission: this.properties.permission,
|
//permission: this.properties.permission, // old way
|
||||||
|
selectedPermissions: this.properties.selectedPermissions.map((spp) => { return { ...spp, isChecked: true }; }),
|
||||||
showHiddenLists: this.properties.showHiddenLists,
|
showHiddenLists: this.properties.showHiddenLists,
|
||||||
showCatalogs: this.properties.showCatalogs,
|
showCatalogs: this.properties.showCatalogs,
|
||||||
showEmail: this.properties.showEmail,
|
showEmail: this.properties.showEmail,
|
||||||
showSecurityGroups: this.properties.showSecurityGroups,
|
showSecurityGroups: this.properties.showSecurityGroups,
|
||||||
showUsers: this.properties.showUsers,
|
showUsers: this.properties.showUsers,
|
||||||
|
showOnlyUsersWithPermission: this.properties.showOnlyUsersWithPermission,
|
||||||
letUserSelectPermission: this.properties.letUserSelectPermission,
|
letUserSelectPermission: this.properties.letUserSelectPermission,
|
||||||
letUserSelectUsers: this.properties.letUserSelectUsers,
|
letUserSelectUsers: this.properties.letUserSelectUsers,
|
||||||
letUserSelectLists: this.properties.letUserSelectLists,
|
letUserSelectLists: this.properties.letUserSelectLists,
|
||||||
|
@ -48,8 +48,8 @@ export default class SpSecurityWebPart extends BaseClientSideWebPart<ISpSecurity
|
||||||
listTitleColumnWidth: this.properties.listTitleColumnWidth,
|
listTitleColumnWidth: this.properties.listTitleColumnWidth,
|
||||||
users: this.properties.users,
|
users: this.properties.users,
|
||||||
getPermissionTypes: this.getPermissionTypes,
|
getPermissionTypes: this.getPermissionTypes,
|
||||||
graphHttpClient: this.context.graphHttpClient,
|
aadHttpClient: null,//this.context.aadHttpClient,
|
||||||
domElement : this.domElement
|
domElement: this.domElement
|
||||||
|
|
||||||
};
|
};
|
||||||
const element: React.ReactElement<ISpSecurityProps> = React.createElement(
|
const element: React.ReactElement<ISpSecurityProps> = React.createElement(
|
||||||
|
@ -75,21 +75,41 @@ export default class SpSecurityWebPart extends BaseClientSideWebPart<ISpSecurity
|
||||||
}
|
}
|
||||||
return perms;
|
return perms;
|
||||||
}
|
}
|
||||||
|
private onPropertyChange(propertyPath: string, oldValue: any, newValue: any) {
|
||||||
|
//debugger;
|
||||||
|
// does this get oldvalue and new value?
|
||||||
|
switch (propertyPath) {
|
||||||
|
case "SelectedPermissions":
|
||||||
|
|
||||||
|
this.properties.selectedPermissions = newValue;
|
||||||
|
|
||||||
|
this.context.propertyPane.refresh();
|
||||||
|
this.render();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||||
return {
|
return {
|
||||||
pages: [
|
pages: [
|
||||||
{
|
{
|
||||||
header: {
|
header: {
|
||||||
description: "Configuration"
|
description: "Permission Configuration"
|
||||||
},
|
},
|
||||||
groups: [
|
groups: [
|
||||||
{
|
{
|
||||||
groupName: "Permission Settings",
|
groupName: "Permission Settings",
|
||||||
groupFields: [
|
groupFields: [
|
||||||
|
|
||||||
PropertyPaneDropdown("permission", {
|
PropertyFieldSelectedPermissions("SelectedPermissions", {
|
||||||
label: "Permission Type",
|
label: "Selected Permissions and Colors",
|
||||||
options: this.getPermissionTypes()
|
onPropertyChange: this.onPropertyChange.bind(this),
|
||||||
|
|
||||||
|
getSelectedPermissions: () => {
|
||||||
|
return this.properties.selectedPermissions || [];
|
||||||
|
},
|
||||||
}),
|
}),
|
||||||
PropertyPaneCheckbox("letUserSelectPermission", {
|
PropertyPaneCheckbox("letUserSelectPermission", {
|
||||||
text: "Let user select Permission"
|
text: "Let user select Permission"
|
||||||
|
@ -112,7 +132,11 @@ export default class SpSecurityWebPart extends BaseClientSideWebPart<ISpSecurity
|
||||||
PropertyPaneCheckbox("showUsers", {
|
PropertyPaneCheckbox("showUsers", {
|
||||||
text: "Show Users"
|
text: "Show Users"
|
||||||
}),
|
}),
|
||||||
|
PropertyPaneToggle("showOnlyUsersWithPermission", {
|
||||||
|
label: "Only show users with permission",
|
||||||
|
onText: "Show users only if they have permission",
|
||||||
|
offText: "Show all users",
|
||||||
|
}),
|
||||||
PropertyPaneCheckbox("letUserSelectUsers", {
|
PropertyPaneCheckbox("letUserSelectUsers", {
|
||||||
text: "Let user select Users"
|
text: "Let user select Users"
|
||||||
})
|
})
|
||||||
|
@ -130,6 +154,42 @@ export default class SpSecurityWebPart extends BaseClientSideWebPart<ISpSecurity
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
header: {
|
||||||
|
description: "Permission Configuration"
|
||||||
|
},
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
groupName: "Permission Settings",
|
||||||
|
groupFields: [
|
||||||
|
|
||||||
|
PropertyFieldSelectedPermissions("SelectedPermissions", {
|
||||||
|
label: "Selected Permissions and Colors",
|
||||||
|
onPropertyChange: this.onPropertyChange.bind(this),
|
||||||
|
|
||||||
|
getSelectedPermissions: () => {
|
||||||
|
return this.properties.selectedPermissions || [];
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
PropertyPaneCheckbox("letUserSelectPermission", {
|
||||||
|
text: "Let user select Permission"
|
||||||
|
}),
|
||||||
|
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
groupName: "Display Settings",
|
||||||
|
groupFields: [
|
||||||
|
PropertyPaneSlider("listTitleColumnWidth", {
|
||||||
|
label: "Initial title column width",
|
||||||
|
min: 1,
|
||||||
|
max: 1000
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
header: {
|
header: {
|
||||||
description: "Configure Lists"
|
description: "Configure Lists"
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
import { SPSiteUser } from "../../SPSecurityService";
|
import { SPSiteUser } from "../../SPSecurityService";
|
||||||
import { SPPermission } from "@microsoft/sp-page-context";
|
import { SPPermission } from "@microsoft/sp-page-context";
|
||||||
import {IPropertyPaneDropdownOption} from "@microsoft/sp-webpart-base";
|
import { } from "@microsoft/sp-webpart-base";
|
||||||
import { GraphHttpClient } from "@microsoft/sp-http";
|
import { IPropertyPaneDropdownOption, PropertyPaneDropdown } from "@microsoft/sp-property-pane";
|
||||||
|
import { AadHttpClient } from "@microsoft/sp-http";
|
||||||
|
import {ISelectedPermission} from "../ISpSecurityWebPartProps";
|
||||||
export interface ISpSecurityProps {
|
export interface ISpSecurityProps {
|
||||||
users: SPSiteUser[];
|
users: SPSiteUser[];
|
||||||
permission: string;
|
//permission: string;
|
||||||
|
selectedPermissions:ISelectedPermission[];
|
||||||
showHiddenLists: boolean;
|
showHiddenLists: boolean;
|
||||||
showCatalogs:boolean;
|
showCatalogs:boolean;
|
||||||
getPermissionTypes:()=> IPropertyPaneDropdownOption[];
|
getPermissionTypes:()=> IPropertyPaneDropdownOption[];
|
||||||
graphHttpClient: GraphHttpClient;
|
aadHttpClient: AadHttpClient;
|
||||||
letUserSelectPermission:boolean;
|
letUserSelectPermission:boolean;
|
||||||
letUserSelectUsers:boolean;
|
letUserSelectUsers:boolean;
|
||||||
letUserSelectLists:boolean;
|
letUserSelectLists:boolean;
|
||||||
|
@ -18,6 +21,7 @@ export interface ISpSecurityProps {
|
||||||
showEmail:boolean; //0 show name, 1 show email
|
showEmail:boolean; //0 show name, 1 show email
|
||||||
showSecurityGroups:boolean; // show PrincipalType=4
|
showSecurityGroups:boolean; // show PrincipalType=4
|
||||||
showUsers:boolean; // show PrincipalType=1
|
showUsers:boolean; // show PrincipalType=1
|
||||||
|
showOnlyUsersWithPermission:boolean; //// toggle to show everyone, or justy the users who have the permissions
|
||||||
domElement:any; // needed to disable button postback after render on classic pages
|
domElement:any; // needed to disable button postback after render on classic pages
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
import { SPSecurityInfo } from "../../SPSecurityService";
|
import { SPSecurityInfo } from "../../SPSecurityService";
|
||||||
|
import { ISelectedPermission } from "../ISpSecurityWebPartProps";
|
||||||
export interface ISpSecurityState {
|
export interface ISpSecurityState {
|
||||||
securityInfo: SPSecurityInfo;
|
securityInfo: SPSecurityInfo;
|
||||||
permission: string;
|
// permission: string;
|
||||||
showUserPanel:boolean;
|
selectedPermissions: ISelectedPermission[];
|
||||||
showListPanel:boolean;
|
showUserPanel: boolean;
|
||||||
showEmail:boolean; //0 show name, 1 show email
|
showListPanel: boolean;
|
||||||
securityInfoLoaded:boolean;
|
showPermissionsPanel: boolean;
|
||||||
|
showEmail: boolean; //0 show name, 1 show email
|
||||||
|
securityInfoLoaded: boolean;
|
||||||
|
errors: Array<string>;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import { Icon } from 'office-ui-fabric-react/lib/Icon';
|
||||||
|
import { Stack, StackItem, Alignment } from 'office-ui-fabric-react/lib/Stack';
|
||||||
|
import { IconButton, DefaultButton, PrimaryButton } from 'office-ui-fabric-react/lib/Button';
|
||||||
|
import { ISelectedPermission } from "../ISpSecurityWebPartProps";
|
||||||
|
export interface ILegendProps {
|
||||||
|
selectedPermissions: Array<ISelectedPermission>;
|
||||||
|
checkUncheckPermission: (perm: ISelectedPermission) => void;
|
||||||
|
}
|
||||||
|
export function Legend(props: ILegendProps): JSX.Element {
|
||||||
|
//debugger;
|
||||||
|
|
||||||
|
return (<Stack horizontal verticalFill wrap={true} gap={3}>
|
||||||
|
{
|
||||||
|
props.selectedPermissions.map((sp) =>
|
||||||
|
<div>
|
||||||
|
<DefaultButton
|
||||||
|
text={sp.freindlyName}
|
||||||
|
onClick={(e) => {
|
||||||
|
props.checkUncheckPermission(sp);
|
||||||
|
}}
|
||||||
|
checked={sp.isChecked}
|
||||||
|
title={sp.freindlyName}
|
||||||
|
iconProps={{ iconName: sp.iconName, style: { color: sp.color } }}>
|
||||||
|
{sp.freindlyName}
|
||||||
|
</DefaultButton>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
// return (<div>
|
||||||
|
// {
|
||||||
|
// props.selectedPermissions.map((sp)=><span><span> {sp.freindlyName} : </span><span><Icon iconName={sp.iconName} style={{color:sp.color?sp.color:"FFFFFF"}} /></span></span> )
|
||||||
|
// }
|
||||||
|
// </div>
|
||||||
|
// );
|
||||||
|
}
|
|
@ -3,8 +3,9 @@
|
||||||
.spSecurity {
|
.spSecurity {
|
||||||
}
|
}
|
||||||
.themecolor {
|
.themecolor {
|
||||||
color: $ms-color-themePrimary;
|
color: $ms-color-themeDarkAlt;
|
||||||
}
|
}
|
||||||
|
|
||||||
.nonbrandeddocumentcolor {
|
.nonbrandeddocumentcolor {
|
||||||
color: "#00FF00";
|
color: "#00FF00";
|
||||||
}
|
}
|
||||||
|
@ -36,7 +37,15 @@
|
||||||
width: 40px !important;
|
width: 40px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.itemTitle {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
:global(.ms-List-cell):nth-child(even) :global(.ms-DetailsRow) {
|
:global(.ms-List-cell):nth-child(even) :global(.ms-DetailsRow) {
|
||||||
background: $ms-color-neutralLight;
|
background: '[theme:neutralLight, default: #eaeaea]';
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: '[theme:neutralLighter, default: #f4f4f4]';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import * as React from "react";
|
||||||
import styles from "./SpSecurity.module.scss";
|
import styles from "./SpSecurity.module.scss";
|
||||||
import { ISpSecurityProps } from "./ISpSecurityProps";
|
import { ISpSecurityProps } from "./ISpSecurityProps";
|
||||||
import { ISpSecurityState } from "./ISpSecurityState";
|
import { ISpSecurityState } from "./ISpSecurityState";
|
||||||
|
import { ILegendProps, Legend } from "./Legend";
|
||||||
import SPSecurityService from "../../SPSecurityService";
|
import SPSecurityService from "../../SPSecurityService";
|
||||||
import { SPListItem, SPList, SPSiteUser, Helpers } from "../../SPSecurityService";
|
import { SPListItem, SPList, SPSiteUser, Helpers } from "../../SPSecurityService";
|
||||||
import { SPPermission } from "@microsoft/sp-page-context";
|
import { SPPermission } from "@microsoft/sp-page-context";
|
||||||
|
@ -11,17 +11,18 @@ import { DetailsList, IColumn, SelectionMode, IDetailsRowProps, Selection } from
|
||||||
import { Icon } from 'office-ui-fabric-react/lib/Icon';
|
import { Icon } from 'office-ui-fabric-react/lib/Icon';
|
||||||
import { Checkbox } from 'office-ui-fabric-react/lib/Checkbox';
|
import { Checkbox } from 'office-ui-fabric-react/lib/Checkbox';
|
||||||
import { CommandBar } from "office-ui-fabric-react/lib/CommandBar";
|
import { CommandBar } from "office-ui-fabric-react/lib/CommandBar";
|
||||||
|
import { Stack } from "office-ui-fabric-react/lib/Stack";
|
||||||
import { Spinner } from "office-ui-fabric-react/lib/Spinner";
|
import { Spinner } from "office-ui-fabric-react/lib/Spinner";
|
||||||
import { IContextualMenuItem, ContextualMenuItemType } from "office-ui-fabric-react/lib/ContextualMenu";
|
import { IContextualMenuItem, ContextualMenuItemType } from "office-ui-fabric-react/lib/ContextualMenu";
|
||||||
|
import { ISelectedPermission } from "../ISpSecurityWebPartProps";
|
||||||
import { Panel, PanelType } from "office-ui-fabric-react/lib/Panel";
|
import { Panel, PanelType } from "office-ui-fabric-react/lib/Panel";
|
||||||
import { right } from "glamor";
|
import SelectedPermissionsPanel from "../containers/SelectedPermissionsPanel";
|
||||||
|
import { css } from "@uifabric/utilities/lib/css";
|
||||||
import {
|
import {
|
||||||
Environment,
|
Environment,
|
||||||
EnvironmentType
|
EnvironmentType
|
||||||
} from '@microsoft/sp-core-library';
|
} from '@microsoft/sp-core-library';
|
||||||
/* tslint:disable */
|
/* tslint:disable */
|
||||||
|
|
||||||
export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSecurityState> {
|
export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSecurityState> {
|
||||||
private svc: SPSecurityService = new SPSecurityService("ss");
|
private svc: SPSecurityService = new SPSecurityService("ss");
|
||||||
private userSelection = new Selection();
|
private userSelection = new Selection();
|
||||||
|
@ -31,11 +32,14 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
securityInfo: { siteUsers: [], siteGroups: [], roleDefinitions: [], lists: [] },
|
securityInfo: { siteUsers: [], siteGroups: [], roleDefinitions: [], lists: [] },
|
||||||
permission: this.props.permission,
|
//permission: this.props.permission,
|
||||||
|
selectedPermissions: this.props.selectedPermissions,
|
||||||
showUserPanel: false,
|
showUserPanel: false,
|
||||||
showListPanel: false,
|
showListPanel: false,
|
||||||
showEmail: this.props.showEmail,
|
showEmail: this.props.showEmail,
|
||||||
securityInfoLoaded: false
|
securityInfoLoaded: false,
|
||||||
|
showPermissionsPanel: false,
|
||||||
|
errors:[]
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -64,19 +68,34 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public componentWillMount(): void {
|
public componentWillReceiveProps(newProps: ISpSecurityProps) {
|
||||||
|
|
||||||
this.svc.loadData(this.props.showHiddenLists, this.props.showCatalogs, this.props.graphHttpClient, false).then((response) => {
|
this.setState((current) => ({
|
||||||
|
...current,
|
||||||
|
selectedPermissions: newProps.selectedPermissions,
|
||||||
|
showEmail: newProps.showEmail
|
||||||
|
}));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public componentWillMount(): void {
|
||||||
|
//debugger;
|
||||||
|
this.svc.loadData(this.props.showHiddenLists, this.props.showCatalogs, this.props.aadHttpClient, false)
|
||||||
|
.then((response) => {
|
||||||
const state: ISpSecurityState = {
|
const state: ISpSecurityState = {
|
||||||
securityInfo: response,
|
securityInfo: response,
|
||||||
permission: this.props.permission,
|
// permission: this.props.permission,
|
||||||
|
selectedPermissions: this.props.selectedPermissions ? this.props.selectedPermissions : [],
|
||||||
showUserPanel: false,
|
showUserPanel: false,
|
||||||
showListPanel: false,
|
showListPanel: false,
|
||||||
|
showPermissionsPanel: false,
|
||||||
showEmail: this.props.showEmail,
|
showEmail: this.props.showEmail,
|
||||||
securityInfoLoaded: true
|
securityInfoLoaded: true,
|
||||||
|
errors:[]
|
||||||
|
|
||||||
};
|
};
|
||||||
// inlclude\exclude lists selected in property pane
|
// inlclude\exclude lists selected in property pane
|
||||||
|
//debugger;
|
||||||
state.securityInfo.lists = state.securityInfo.lists.filter((list) => {
|
state.securityInfo.lists = state.securityInfo.lists.filter((list) => {
|
||||||
if (this.props.includeAdminSelectedLists) { // include the lists
|
if (this.props.includeAdminSelectedLists) { // include the lists
|
||||||
|
|
||||||
|
@ -96,8 +115,9 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.setState(state);
|
this.setState(state);
|
||||||
}).catch((err) => {
|
}).catch((errors:Array<string>) => {
|
||||||
debugger;
|
this.setState((current)=>({...current,errors:errors,securityInfoLoaded:true}))
|
||||||
|
//debugger;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
public expandList(item: any): any {
|
public expandList(item: any): any {
|
||||||
|
@ -135,8 +155,10 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
||||||
item.isFetched = true;
|
item.isFetched = true;
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
|
|
||||||
}).catch((err) => {
|
}).catch((error) => {
|
||||||
debugger;
|
let errors=this.state.errors;
|
||||||
|
errors.push(`There was an error fetching site users -- ${error.message}`);
|
||||||
|
this.setState((current)=>({...current,errors:errors}))
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -180,30 +202,27 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderItemTitle(item?: any, index?: number, column?: IColumn): any {
|
public renderItemTitle(item?: any, index?: number, column?: IColumn): any {
|
||||||
let extension = item.title.split('.').pop();
|
const extension = item.title.split('.').pop();
|
||||||
let classname = "ms-u-smOffset" + (item.level);
|
const isValidExtension: boolean = (this.validBrandIcons.indexOf(" " + extension + " ") !== -1);
|
||||||
if (this.validBrandIcons.indexOf(" " + extension + " ") !== -1) {
|
const classname = css("ms-u-smOffset" + (item.level), isValidExtension ?
|
||||||
classname += " ms-Icon ms-BrandIcon--" + extension + " ms-BrandIcon--icon16 ";
|
`ms-Icon ms-BrandIcon--${extension} ms-BrandIcon--icon16`:
|
||||||
}
|
`ms-Icon ms-Icon--TextDocument ${styles.themecolor}`);
|
||||||
else {
|
|
||||||
classname += " ms-Icon ms-Icon--TextDocument " + styles.themecolor;
|
return (
|
||||||
}
|
<div className={styles.itemTitle} >
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<div className={classname} />
|
<div className={classname} />
|
||||||
<span > {item.title}</span>
|
<span> {item.title}</span>
|
||||||
</div>);
|
</div>);
|
||||||
}
|
}
|
||||||
public renderListTitle(item?: any, index?: number, column?: IColumn): any {
|
public renderListTitle(item?: any, index?: number, column?: IColumn): any {
|
||||||
|
|
||||||
let classname = " ms-Icon ";
|
const classname = css("ms-Icon", styles.themecolor, item.itemCount > 0 ?
|
||||||
if (item.itemCount > 0) {
|
'ms-Icon ms-Icon--FabricFormLibrary':
|
||||||
classname += " ms-Icon ms-Icon--FabricFormLibrary " + styles.themecolor;
|
'ms-Icon ms-Icon--FabricFolder');
|
||||||
} else {
|
|
||||||
classname += " ms-Icon ms-Icon--FabricFolder ";
|
|
||||||
}
|
|
||||||
return (
|
return (
|
||||||
<div onClick={(e) => {
|
<div className={styles.itemTitle} onClick={(e) => {
|
||||||
|
//debugger;
|
||||||
this.expandCollapseList(item);
|
this.expandCollapseList(item);
|
||||||
}}>
|
}}>
|
||||||
<div className={classname} />
|
<div className={classname} />
|
||||||
|
@ -213,15 +232,12 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
||||||
|
|
||||||
}
|
}
|
||||||
public renderFolderTitle(item?: any, index?: number, column?: IColumn): any {
|
public renderFolderTitle(item?: any, index?: number, column?: IColumn): any {
|
||||||
let classname = "ms-u-smOffset" + (item.level);
|
const classname = css("ms-u-smOffset" + (item.level),styles.themecolor, item.itemCount > 0 ?
|
||||||
if (item.itemCount > 0) {
|
'ms-Icon ms-Icon--FabricFormLibrary':
|
||||||
classname += " ms-Icon ms-Icon--FabricFormLibrary " + styles.themecolor;
|
'ms-Icon ms-Icon--FabricFolder');
|
||||||
} else {
|
|
||||||
classname += " ms-Icon ms-Icon--FabricFolder ";
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div onClick={(e) => {
|
<div className={styles.itemTitle} onClick={(e) => {
|
||||||
this.expandCollapseList(item);
|
this.expandCollapseList(item);
|
||||||
}}>
|
}}>
|
||||||
<div className={classname} />
|
<div className={classname} />
|
||||||
|
@ -241,55 +257,31 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
// public getIcon(item?: any, index?: number, column?: IColumn): string {
|
|
||||||
// debugger;
|
|
||||||
// let classname: string = "";
|
|
||||||
// if (item instanceof SPList || item.type==="Folder") {
|
|
||||||
// if (item.itemCount === 0) {
|
|
||||||
// return "FabricFolderFill";
|
|
||||||
// } else {
|
|
||||||
// return "FabricFolder";
|
|
||||||
// }
|
|
||||||
// } else{
|
|
||||||
// return "ms-Icon ms-Icon--ExcelDocument"
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
public renderUserItem(item: any, index: number, column: IColumn,effectivePermissions:ISelectedPermission[]): any {
|
||||||
// public renderTitle(item?: any, index?: number, column?: IColumn): any {
|
|
||||||
// let classname: string = "";
|
|
||||||
// if (item instanceof SPListItem) {
|
|
||||||
// classname = "ms-u-smOffset" + (item.level);
|
|
||||||
// }
|
|
||||||
// return (
|
|
||||||
// <div className={classname}>
|
|
||||||
// <div style={{ float: "left" }}>
|
|
||||||
// <Icon iconName={this.getIcon(item, index, column)} onClick={(e) => {
|
|
||||||
// this.expandCollapseList(item);
|
|
||||||
// }} />
|
|
||||||
// </div>
|
|
||||||
// <div> {item.title}</div>
|
|
||||||
// <div style={{ clear: "both" }} />
|
|
||||||
// </div>
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
public renderUserItem(item?: any, index?: number, column?: IColumn): any {
|
|
||||||
let user: SPSiteUser = find(this.state.securityInfo.siteUsers, (su) => {
|
let user: SPSiteUser = find(this.state.securityInfo.siteUsers, (su) => {
|
||||||
return su.id.toString() === column.key;
|
return su.id.toString() === column.key;
|
||||||
});
|
});
|
||||||
if (Helpers.doesUserHavePermission(item, user, SPPermission[this.state.permission],
|
// spin througg the selected permsiisopns and for the first hit, display that color. No Hit, then display empty
|
||||||
this.state.securityInfo.roleDefinitions, this.state.securityInfo.siteGroups)) {
|
|
||||||
return (
|
for (let selectedPermission of effectivePermissions ? effectivePermissions : []) {
|
||||||
<Icon iconName="CircleFill" onClick={(e) => {
|
if (Helpers.doesUserHavePermission(item, user, SPPermission[selectedPermission.permission],
|
||||||
this.expandCollapseList(item);
|
this.state.securityInfo.roleDefinitions, this.state.securityInfo.siteGroups)) {
|
||||||
}} />
|
return (
|
||||||
);
|
<Icon iconName={selectedPermission.iconName} style={{ color: selectedPermission.color }} onClick={(e) => {
|
||||||
} else {
|
this.expandCollapseList(item);
|
||||||
return (
|
}} />
|
||||||
<Icon iconName="LocationCircle" onClick={(e) => {
|
);
|
||||||
this.expandCollapseList(item);
|
}
|
||||||
}} />
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
// no hits
|
||||||
|
return (
|
||||||
|
<Icon iconName={item.iconName} onClick={(e) => {
|
||||||
|
this.expandCollapseList(item);
|
||||||
|
}} />
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
public renderUserSelected(item?: SPSiteUser, index?: number, column?: IColumn): any {
|
public renderUserSelected(item?: SPSiteUser, index?: number, column?: IColumn): any {
|
||||||
|
|
||||||
|
@ -298,7 +290,7 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
public addUserColumns(columns: IColumn[], users: SPSiteUser[]): IColumn[] {
|
public addUserColumns(columns: IColumn[], users: SPSiteUser[],effectivePermissions:ISelectedPermission[]): IColumn[] {
|
||||||
for (let user of users) {
|
for (let user of users) {
|
||||||
if (user.isSelected) {
|
if (user.isSelected) {
|
||||||
if (
|
if (
|
||||||
|
@ -306,15 +298,20 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
||||||
||
|
||
|
||||||
(user.principalType === 4 && this.props.showSecurityGroups)
|
(user.principalType === 4 && this.props.showSecurityGroups)
|
||||||
)
|
)
|
||||||
columns.push({
|
if (!this.props.showOnlyUsersWithPermission || Helpers.doesUserHaveAnyPermission(this.state.securityInfo.lists, user, effectivePermissions.map((sp) => { return SPPermission[sp.permission] }), this.state.securityInfo.roleDefinitions, this.state.securityInfo.siteGroups))
|
||||||
key: user.id.toString(),
|
columns.push({
|
||||||
name: this.state.showEmail ? user.upn : user.name,
|
key: user.id.toString(),
|
||||||
fieldName: "",
|
name: this.state.showEmail ? user.upn : user.name,
|
||||||
minWidth: 20,
|
fieldName: "",
|
||||||
maxWidth: 20,
|
minWidth: 20,
|
||||||
onRender: this.renderUserItem,
|
maxWidth: 20,
|
||||||
headerClassName: styles.rotatedColumnHeader,
|
onRender: (item?: any, index?: number, column?: IColumn)=>{
|
||||||
});
|
//debugger;
|
||||||
|
return this.renderUserItem(item,index,column,effectivePermissions);
|
||||||
|
},
|
||||||
|
headerClassName: styles.rotatedColumnHeader,
|
||||||
|
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return columns;
|
return columns;
|
||||||
|
@ -362,7 +359,17 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
private checkUncheckPermission(perm: ISelectedPermission) {
|
||||||
|
//debugger;
|
||||||
|
var sps = this.state.selectedPermissions;
|
||||||
|
const idx = findIndex(sps, (sp: ISelectedPermission) => { return sp.permission == perm.permission; });
|
||||||
|
if (idx != -1) {
|
||||||
|
sps[idx].isChecked = !sps[idx].isChecked
|
||||||
|
this.setState((current) => ({ ...current, SelectedPermissions: [...sps] }));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
public render(): React.ReactElement<ISpSecurityProps> {
|
public render(): React.ReactElement<ISpSecurityProps> {
|
||||||
if (!this.state.securityInfoLoaded) {
|
if (!this.state.securityInfoLoaded) {
|
||||||
return (
|
return (
|
||||||
|
@ -372,7 +379,6 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
debugger;
|
|
||||||
let userPanelCommands: IContextualMenuItem[] = [];
|
let userPanelCommands: IContextualMenuItem[] = [];
|
||||||
userPanelCommands.push({
|
userPanelCommands.push({
|
||||||
icon: "BoxAdditionSolid",
|
icon: "BoxAdditionSolid",
|
||||||
|
@ -380,11 +386,9 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
||||||
name: "Add All Users",
|
name: "Add All Users",
|
||||||
itemType: ContextualMenuItemType.Normal,
|
itemType: ContextualMenuItemType.Normal,
|
||||||
onClick: (event, item) => {
|
onClick: (event, item) => {
|
||||||
|
|
||||||
for (let item of this.state.securityInfo.siteUsers) {
|
for (let item of this.state.securityInfo.siteUsers) {
|
||||||
item.isSelected = true;
|
item.isSelected = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.setState(this.state);
|
this.setState(this.state);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -434,22 +438,17 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
||||||
});
|
});
|
||||||
let commands: IContextualMenuItem[] = [];
|
let commands: IContextualMenuItem[] = [];
|
||||||
if (this.props.letUserSelectPermission) {
|
if (this.props.letUserSelectPermission) {
|
||||||
commands.push({
|
|
||||||
title: "Permission",
|
|
||||||
name: "Permission:",
|
|
||||||
key:
|
|
||||||
"permissionlabel"
|
|
||||||
|
|
||||||
})
|
|
||||||
commands.push({
|
commands.push({
|
||||||
icon: "AzureKeyVault",
|
icon: "AzureKeyVault",
|
||||||
key: "SecurityLevel",
|
key: "SecurityLevel2",
|
||||||
title: "Permission",
|
name: "Permission",
|
||||||
label: "sss",
|
|
||||||
name: this.state.permission ? this.state.permission : "Select Permission",
|
|
||||||
itemType: ContextualMenuItemType.Normal,
|
itemType: ContextualMenuItemType.Normal,
|
||||||
items: this.getPermissionLevels()
|
onClick: (event, item) => {
|
||||||
});
|
this.setState((current) => ({ ...current, showPermissionsPanel: !current.showPermissionsPanel }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (this.props.letUserSelectUsers) {
|
if (this.props.letUserSelectUsers) {
|
||||||
commands.push({
|
commands.push({
|
||||||
|
@ -480,26 +479,24 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
||||||
title: "DisplayMode",
|
title: "DisplayMode",
|
||||||
name: this.state.showEmail ? "Show Email" : "Show Name",
|
name: this.state.showEmail ? "Show Email" : "Show Name",
|
||||||
itemType: ContextualMenuItemType.Normal,
|
itemType: ContextualMenuItemType.Normal,
|
||||||
items: [{
|
subMenuProps: {
|
||||||
key: "ShowName",
|
items: [{
|
||||||
name: "Show Name",
|
key: "ShowName",
|
||||||
onClick: (event, item) => {
|
name: "Show Name",
|
||||||
debugger;
|
onClick: (event, item) => {
|
||||||
this.setState((current) => ({ ...current, showEmail: false }));
|
this.setState((current) => ({ ...current, showEmail: false }));
|
||||||
}
|
}
|
||||||
|
},
|
||||||
},
|
{
|
||||||
{
|
key: "ShowEmail",
|
||||||
key: "ShowEmail",
|
name: "Show Email",
|
||||||
name: "Show Email",
|
onClick: (event, item) => {
|
||||||
onClick: (event, item) => {
|
this.setState((current) => ({ ...current, showEmail: true }));
|
||||||
debugger;
|
}
|
||||||
this.setState((current) => ({ ...current, showEmail: true }));
|
}]
|
||||||
}
|
}
|
||||||
|
|
||||||
}]
|
|
||||||
});
|
});
|
||||||
|
let effectivePermissions=this.state.selectedPermissions.filter((sp)=>{ return sp.isChecked;})
|
||||||
let columns: Array<IColumn> = [
|
let columns: Array<IColumn> = [
|
||||||
{
|
{
|
||||||
key: "title", name: "Title", isResizable: true, fieldName: "title",
|
key: "title", name: "Title", isResizable: true, fieldName: "title",
|
||||||
|
@ -507,7 +504,7 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
||||||
onRender: this.renderTitle, isRowHeader: true
|
onRender: this.renderTitle, isRowHeader: true
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
let displayColumns: IColumn[] = this.addUserColumns(columns, this.state.securityInfo.siteUsers);
|
let displayColumns: IColumn[] = this.addUserColumns(columns, this.state.securityInfo.siteUsers,effectivePermissions);
|
||||||
|
|
||||||
|
|
||||||
let displayItems: (SPList | SPListItem)[] = filter(this.state.securityInfo.lists, (item) => {
|
let displayItems: (SPList | SPListItem)[] = filter(this.state.securityInfo.lists, (item) => {
|
||||||
|
@ -518,17 +515,49 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
let errorMessages=[];
|
||||||
|
for (let error of this.state.errors){
|
||||||
|
errorMessages.push(<li>{error}</li>)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div >
|
<div >
|
||||||
|
<ul>{errorMessages}</ul>
|
||||||
<CommandBar
|
<CommandBar
|
||||||
items={commands}
|
items={commands}
|
||||||
/>
|
/>
|
||||||
|
<br />
|
||||||
|
<Legend
|
||||||
|
selectedPermissions={this.state.selectedPermissions}
|
||||||
|
checkUncheckPermission={(e) => {
|
||||||
|
//debugger;
|
||||||
|
this.checkUncheckPermission(e);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/>
|
||||||
<DetailsList
|
<DetailsList
|
||||||
items={displayItems}
|
items={displayItems}
|
||||||
columns={displayColumns}
|
columns={displayColumns}
|
||||||
selectionMode={SelectionMode.none}
|
selectionMode={SelectionMode.none}
|
||||||
className={styles.SPFXSecurityGrid}
|
className={styles.SPFXSecurityGrid}
|
||||||
|
|
||||||
/>
|
/>
|
||||||
|
<SelectedPermissionsPanel
|
||||||
|
isOpen={this.state.showPermissionsPanel}
|
||||||
|
SelectedPermissions={this.props.selectedPermissions}
|
||||||
|
onPropertyChange={(propertyName: string, oldValue: Array<ISelectedPermission>, newValue: Array<ISelectedPermission>) => {
|
||||||
|
|
||||||
|
this.setState((current) => ({ ...current, selectedPermissions: newValue }));
|
||||||
|
}}
|
||||||
|
closePanel={() => {
|
||||||
|
|
||||||
|
this.setState((current) => ({ ...current, showPermissionsPanel: false }));
|
||||||
|
}}
|
||||||
|
|
||||||
|
>
|
||||||
|
|
||||||
|
</SelectedPermissionsPanel>
|
||||||
<Panel
|
<Panel
|
||||||
isBlocking={false}
|
isBlocking={false}
|
||||||
isOpen={this.state.showUserPanel}
|
isOpen={this.state.showUserPanel}
|
||||||
|
@ -561,6 +590,7 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
||||||
headerText='Select Lists'
|
headerText='Select Lists'
|
||||||
closeButtonAriaLabel='Close'>
|
closeButtonAriaLabel='Close'>
|
||||||
<CommandBar items={listPanelCommands} />
|
<CommandBar items={listPanelCommands} />
|
||||||
|
|
||||||
<DetailsList
|
<DetailsList
|
||||||
|
|
||||||
selection={this.listSelection}
|
selection={this.listSelection}
|
||||||
|
|
|
@ -0,0 +1,208 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import { Button, PrimaryButton } from 'office-ui-fabric-react/lib/Button';
|
||||||
|
import { Dropdown, IDropdownOption } from "office-ui-fabric-react/lib/Dropdown";
|
||||||
|
import { ColorPicker } from "office-ui-fabric-react/lib/ColorPicker";
|
||||||
|
import { IColor } from "office-ui-fabric-react/lib/Color";
|
||||||
|
import { Dialog } from "office-ui-fabric-react/lib/Dialog";
|
||||||
|
import { TextField } from "office-ui-fabric-react/lib/TextField";
|
||||||
|
import { Icon } from "office-ui-fabric-react/lib/Icon";
|
||||||
|
import { ComboBox, IComboBox, IComboBoxOption, } from "office-ui-fabric-react/lib/ComboBox";
|
||||||
|
import { Label } from 'office-ui-fabric-react/lib/Label';
|
||||||
|
import { ISelectedPermission } from "../ISpSecurityWebPartProps";
|
||||||
|
import { SPPermission } from "@microsoft/sp-page-context";
|
||||||
|
import { findIndex } from "lodash";
|
||||||
|
export interface IColorIconSelectorPanelProps {
|
||||||
|
isOpen: boolean;
|
||||||
|
onPermissionChange(color: ISelectedPermission): void;
|
||||||
|
closePanel(): void;
|
||||||
|
title: string;
|
||||||
|
subText: string;
|
||||||
|
currentPerm: ISelectedPermission;
|
||||||
|
SelectedPermissions: ISelectedPermission[];
|
||||||
|
}
|
||||||
|
export interface IColorIconSelectionPanelState {
|
||||||
|
currentPerm: ISelectedPermission;
|
||||||
|
}
|
||||||
|
export default class ColorIconSelectionPanel extends React.Component<IColorIconSelectorPanelProps, IColorIconSelectionPanelState> {
|
||||||
|
|
||||||
|
private iconNames = [
|
||||||
|
"Add",
|
||||||
|
"Back",
|
||||||
|
"BlockContact",
|
||||||
|
"Cancel",
|
||||||
|
"Cat",
|
||||||
|
"CheckBox",
|
||||||
|
"CheckBoxComposite",
|
||||||
|
"CheckMark",
|
||||||
|
"ChevronDown",
|
||||||
|
"ChevronUp",
|
||||||
|
"CircleFill",
|
||||||
|
"CircleRing",
|
||||||
|
"Clear",
|
||||||
|
"Contact",
|
||||||
|
"Contrast",
|
||||||
|
"Delete",
|
||||||
|
"Design",
|
||||||
|
"eDiscovery",
|
||||||
|
"Edit",
|
||||||
|
"EditSolid12",
|
||||||
|
"Emoji2",
|
||||||
|
"Error",
|
||||||
|
"FavoriteStar",
|
||||||
|
"FavoriteStarFill",
|
||||||
|
"Glasses",
|
||||||
|
"HomeSolid",
|
||||||
|
"IncidentTriangle",
|
||||||
|
"LaptopSecure",
|
||||||
|
"LifeSaver",
|
||||||
|
"LifeSaverLock",
|
||||||
|
"Lock",
|
||||||
|
"LockSolid",
|
||||||
|
"Mail",
|
||||||
|
"More",
|
||||||
|
"PageLink",
|
||||||
|
"People",
|
||||||
|
"PeopleAdd",
|
||||||
|
"Permissions",
|
||||||
|
"PinSolid12",
|
||||||
|
"RedEye",
|
||||||
|
"Sad",
|
||||||
|
"SecurityGroup",
|
||||||
|
"Settings",
|
||||||
|
"Share",
|
||||||
|
"Sync",
|
||||||
|
"TriangleSolid",
|
||||||
|
"UnEditable",
|
||||||
|
"UnEditable2",
|
||||||
|
"Unlock",
|
||||||
|
"UserWarning",
|
||||||
|
"View",
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
];
|
||||||
|
constructor(props: IColorIconSelectorPanelProps) {
|
||||||
|
super(props);
|
||||||
|
//debugger;
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
currentPerm: this.props.currentPerm
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private saveChanges(): void {
|
||||||
|
this.props.onPermissionChange(this.state.currentPerm);
|
||||||
|
this.onClosePanel();
|
||||||
|
}
|
||||||
|
|
||||||
|
private onClosePanel(element?: any): void {
|
||||||
|
this.props.closePanel();
|
||||||
|
}
|
||||||
|
private renderIcon(props?, defaultRender?: (props?) => JSX.Element | null): JSX.Element {
|
||||||
|
|
||||||
|
return (<div>
|
||||||
|
<Icon iconName={props.text} /> {props.text}
|
||||||
|
</div>);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private getIconOptions(): IComboBoxOption[] {
|
||||||
|
let options: IComboBoxOption[] = [];
|
||||||
|
for (var iconName of this.iconNames) {
|
||||||
|
var option: IComboBoxOption = {
|
||||||
|
key: iconName, text: iconName,
|
||||||
|
};
|
||||||
|
options.push(option);
|
||||||
|
}
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
public getPermissionTypes(): IDropdownOption[] {
|
||||||
|
let perms = new Array<IDropdownOption>();
|
||||||
|
for (const perm in SPPermission) {
|
||||||
|
if (typeof (SPPermission[perm]) === "object") {
|
||||||
|
perms.push({
|
||||||
|
text: perm,
|
||||||
|
key: perm,
|
||||||
|
disabled: findIndex(this.props.SelectedPermissions, (sp: ISelectedPermission) => { return sp.permission == perm; }) !== -1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return perms;
|
||||||
|
}
|
||||||
|
public render(): JSX.Element {
|
||||||
|
|
||||||
|
//Renders content
|
||||||
|
return (
|
||||||
|
|
||||||
|
<Dialog
|
||||||
|
isOpen={this.props.isOpen}
|
||||||
|
onDismiss={() => this.onClosePanel()}
|
||||||
|
title={this.props.title}
|
||||||
|
subText={this.props.subText}
|
||||||
|
>
|
||||||
|
<Dropdown label="Permission"
|
||||||
|
options={this.getPermissionTypes()}
|
||||||
|
defaultSelectedKey={this.state.currentPerm.permission}
|
||||||
|
onChange={(event: React.FormEvent<HTMLDivElement>, option?: IDropdownOption, index?: number) => {
|
||||||
|
this.state.currentPerm.permission = option.text;
|
||||||
|
this.setState((current) => ({ ...current, currentPerm: this.state.currentPerm }));
|
||||||
|
}}>
|
||||||
|
</Dropdown>
|
||||||
|
<TextField label="Friendly Name"
|
||||||
|
defaultValue={this.state.currentPerm.freindlyName}
|
||||||
|
onChange={(event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>, newValue?: string) => {
|
||||||
|
this.state.currentPerm.freindlyName = newValue;
|
||||||
|
this.setState((current) => ({ ...current, currentPerm: this.state.currentPerm }));
|
||||||
|
}}>
|
||||||
|
</TextField>
|
||||||
|
<Label>Color:</Label>
|
||||||
|
<ColorPicker
|
||||||
|
color={this.state.currentPerm.color}
|
||||||
|
onChange={(event: React.FormEvent<HTMLDivElement>, color: IColor) => {
|
||||||
|
this.state.currentPerm.color = color.str;
|
||||||
|
this.setState((current) => ({ ...current, currentPerm: this.state.currentPerm }));
|
||||||
|
}}>
|
||||||
|
</ColorPicker>
|
||||||
|
<ComboBox allowFreeform={true}
|
||||||
|
|
||||||
|
label="Select Icon(or enter name of a Fabric Icon):"
|
||||||
|
options={this.getIconOptions()}
|
||||||
|
onRenderOption={this.renderIcon}
|
||||||
|
text={this.state.currentPerm.iconName}
|
||||||
|
onChange={(event: React.FormEvent<IComboBox>, option?: IComboBoxOption, index?: number, value?: string) => {
|
||||||
|
//debugger;
|
||||||
|
this.state.currentPerm.iconName = value ? value : option.text;
|
||||||
|
this.setState((current) => ({ ...current, currentPerm: this.state.currentPerm }));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<Label>Display:</Label>
|
||||||
|
<Icon iconName={this.state.currentPerm.iconName} style={{ color: this.state.currentPerm.color }} />
|
||||||
|
<br></br>
|
||||||
|
<br></br>
|
||||||
|
<Button onClick={() => {
|
||||||
|
this.onClosePanel();
|
||||||
|
}}>Cancel</Button>
|
||||||
|
<PrimaryButton
|
||||||
|
disabled={
|
||||||
|
this.state.currentPerm.color == null ||
|
||||||
|
this.state.currentPerm.freindlyName == null ||
|
||||||
|
this.state.currentPerm.iconName == null ||
|
||||||
|
this.state.currentPerm.permission == null
|
||||||
|
}
|
||||||
|
onClick={() => {
|
||||||
|
//debugger;
|
||||||
|
this.saveChanges();
|
||||||
|
}}
|
||||||
|
>Save</PrimaryButton>
|
||||||
|
|
||||||
|
</Dialog>
|
||||||
|
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,73 @@
|
||||||
|
import { ISelectedPermission } from "../ISpSecurityWebPartProps";
|
||||||
|
import * as React from 'react';
|
||||||
|
import * as ReactDom from 'react-dom';
|
||||||
|
import { IPropertyPaneField, IPropertyPaneCustomFieldProps } from "@microsoft/sp-property-pane";
|
||||||
|
import PropertyFieldSelectedPermissionsHost, { IPropertyFieldSelectedPermissionsHostProps } from './PropertyFieldSelectedPermissionsHost';
|
||||||
|
|
||||||
|
export interface IPropertyFieldSelectedPermissionsProps {
|
||||||
|
label: string;
|
||||||
|
initialValue?: Array<ISelectedPermission>;
|
||||||
|
onPropertyChange(propertyPath: string, oldValue: any, newValue: any): void;
|
||||||
|
getSelectedPermissions: () => Array<ISelectedPermission>;
|
||||||
|
}
|
||||||
|
export interface IPropertyFieldSelectedPermissionsPropsInternal extends IPropertyPaneCustomFieldProps {
|
||||||
|
label: string;
|
||||||
|
initialValue?: Array<ISelectedPermission>;
|
||||||
|
targetProperty: string;
|
||||||
|
onRender(elem: HTMLElement): void;
|
||||||
|
onDispose(elem: HTMLElement): void;
|
||||||
|
onPropertyChange(propertyPath: string, oldValue: any, newValue: any): void;
|
||||||
|
SelectedPermissions: Array<ISelectedPermission>;
|
||||||
|
}
|
||||||
|
class PropertyFieldSelectedPermissionsBuilder implements IPropertyPaneField<IPropertyFieldSelectedPermissionsPropsInternal> {
|
||||||
|
//Properties defined by IPropertyPaneField
|
||||||
|
public type = 1;//IPropertyPaneFieldType.Custom;
|
||||||
|
public targetProperty: string;
|
||||||
|
public properties: IPropertyFieldSelectedPermissionsPropsInternal;
|
||||||
|
//Custom properties
|
||||||
|
private label: string;
|
||||||
|
private onPropertyChange: (propertyPath: string, oldValue: any, newValue: any) => void;
|
||||||
|
private customProperties: any;
|
||||||
|
|
||||||
|
public constructor(_targetProperty: string, _properties: IPropertyFieldSelectedPermissionsPropsInternal) {
|
||||||
|
|
||||||
|
this.render = this.render.bind(this);
|
||||||
|
this.properties = _properties;
|
||||||
|
this.label = _properties.label;
|
||||||
|
this.properties.onDispose = this.dispose;
|
||||||
|
this.properties.onRender = this.render;
|
||||||
|
this.onPropertyChange = _properties.onPropertyChange;
|
||||||
|
this.customProperties = _properties.SelectedPermissions ? _properties.SelectedPermissions : [];
|
||||||
|
}
|
||||||
|
|
||||||
|
private render(elem: HTMLElement): void {
|
||||||
|
// what other args does this get? does it get ctx and a callback?
|
||||||
|
const element: React.ReactElement<IPropertyFieldSelectedPermissionsHostProps> = React.createElement(PropertyFieldSelectedPermissionsHost, {
|
||||||
|
label: this.label,
|
||||||
|
onPropertyChange: this.onPropertyChange,
|
||||||
|
SelectedPermissions: this.customProperties,
|
||||||
|
|
||||||
|
});
|
||||||
|
ReactDom.render(element, elem);
|
||||||
|
}
|
||||||
|
private dispose(elem: HTMLElement): void {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export function PropertyFieldSelectedPermissions(targetProperty: string, properties: IPropertyFieldSelectedPermissionsProps): IPropertyPaneField<IPropertyFieldSelectedPermissionsPropsInternal> {
|
||||||
|
//Create an internal properties object from the given properties
|
||||||
|
var newProperties: IPropertyFieldSelectedPermissionsPropsInternal = {
|
||||||
|
label: properties.label,
|
||||||
|
targetProperty: targetProperty,
|
||||||
|
key: targetProperty,
|
||||||
|
initialValue: properties.initialValue,
|
||||||
|
onPropertyChange: properties.onPropertyChange,
|
||||||
|
SelectedPermissions: properties.getSelectedPermissions(),
|
||||||
|
onDispose: null,
|
||||||
|
onRender: null,
|
||||||
|
};
|
||||||
|
//Calles the PropertyFieldSelectedPermissions builder object
|
||||||
|
//This object will simulate a PropertyFieldCustom to manage his rendering process
|
||||||
|
return new PropertyFieldSelectedPermissionsBuilder(targetProperty, newProperties);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
|
||||||
|
|
||||||
|
import { ISelectedPermission } from "../ISpSecurityWebPartProps";
|
||||||
|
import * as React from 'react';
|
||||||
|
import { Label } from 'office-ui-fabric-react/lib/Label';
|
||||||
|
import { Button } from 'office-ui-fabric-react/lib/Button';
|
||||||
|
|
||||||
|
import { Icon } from 'office-ui-fabric-react/lib/Icon';
|
||||||
|
|
||||||
|
import { DetailsList, IColumn, DetailsListLayoutMode, SelectionMode } from "office-ui-fabric-react/lib/DetailsList";
|
||||||
|
import { IDropdownOption } from "office-ui-fabric-react/lib/Dropdown";
|
||||||
|
|
||||||
|
|
||||||
|
import { SPPermission } from "@microsoft/sp-page-context";
|
||||||
|
|
||||||
|
import SelectedPermissionsPanel from "./SelectedPermissionsPanel";
|
||||||
|
export interface IPropertyFieldSelectedPermissionsHostProps {
|
||||||
|
label: string;
|
||||||
|
initialValue?: Array<ISelectedPermission>;
|
||||||
|
onPropertyChange(propertyPath: string, oldValue: any, newValue: any): void;
|
||||||
|
SelectedPermissions: Array<ISelectedPermission>;
|
||||||
|
}
|
||||||
|
export interface IPropertyFieldSelectedPermissionsHostState {
|
||||||
|
openPanel?: boolean;
|
||||||
|
SelectedPermissions: Array<ISelectedPermission>;
|
||||||
|
}
|
||||||
|
export default class PropertyFieldSelectedPermissionsHost extends React.Component<IPropertyFieldSelectedPermissionsHostProps, IPropertyFieldSelectedPermissionsHostState> {
|
||||||
|
public panelColumns: IColumn[] = [
|
||||||
|
{
|
||||||
|
key: 'permission',
|
||||||
|
name: 'Permission',
|
||||||
|
fieldName: 'permission',
|
||||||
|
minWidth: 100,
|
||||||
|
maxWidth: 100,
|
||||||
|
isResizable: true,
|
||||||
|
onRender: (item?: any, index?: number, column?: IColumn) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{item.permission}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'freindlyName',
|
||||||
|
name: 'Name in Legend',
|
||||||
|
fieldName: 'freindlyName',
|
||||||
|
minWidth: 90,
|
||||||
|
maxWidth: 90,
|
||||||
|
isResizable: true,
|
||||||
|
onRender: (item?: any, index?: number, column?: IColumn) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{item.freindlyName}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'color',
|
||||||
|
name: 'Display',
|
||||||
|
fieldName: 'color',
|
||||||
|
minWidth: 50,
|
||||||
|
maxWidth: 50,
|
||||||
|
isResizable: false,
|
||||||
|
onRender: (item?: ISelectedPermission, index?: number, column?: IColumn) => {
|
||||||
|
return (
|
||||||
|
<Icon iconName={item.iconName} style={{ color: item.color }} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
constructor(props: IPropertyFieldSelectedPermissionsHostProps) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
SelectedPermissions: this.props.SelectedPermissions,
|
||||||
|
openPanel: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public getPermissionTypes(): IDropdownOption[] {
|
||||||
|
let perms = new Array();
|
||||||
|
for (const perm in SPPermission) {
|
||||||
|
if (typeof (SPPermission[perm]) === "object") {
|
||||||
|
perms.push({
|
||||||
|
text: perm,
|
||||||
|
key: perm
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return perms;
|
||||||
|
}
|
||||||
|
private onOpenPanel(element?: any): void {
|
||||||
|
this.setState((current) => ({ ...current, openPanel: true }));
|
||||||
|
}
|
||||||
|
private onClosePanel(element?: any): void {
|
||||||
|
//debugger;
|
||||||
|
this.setState((current) => ({ ...current, openPanel: false }));
|
||||||
|
}
|
||||||
|
public render(): JSX.Element {
|
||||||
|
//debugger;
|
||||||
|
//This Details list Renders the short list of permissions in the panel
|
||||||
|
return (
|
||||||
|
<div style={{ marginBottom: '8px' }}>
|
||||||
|
<Label>{this.props.label}</Label>
|
||||||
|
<DetailsList
|
||||||
|
items={this.state.SelectedPermissions}
|
||||||
|
columns={this.panelColumns}
|
||||||
|
layoutMode={DetailsListLayoutMode.justified}
|
||||||
|
selectionMode={SelectionMode.none}
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
onClick={(e) => this.onOpenPanel()}>
|
||||||
|
Edit Permissions and Colors
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<SelectedPermissionsPanel
|
||||||
|
isOpen={this.state.openPanel}
|
||||||
|
onPropertyChange={(prop, oldval, newval) => {
|
||||||
|
this.setState((current) => ({ ...current, SelectedPermissions: [...newval] }));
|
||||||
|
this.props.onPropertyChange("SelectedPermissions", this.props.SelectedPermissions, newval);
|
||||||
|
|
||||||
|
|
||||||
|
}}
|
||||||
|
closePanel={() => { this.onClosePanel(); }}
|
||||||
|
SelectedPermissions={this.props.SelectedPermissions}
|
||||||
|
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,289 @@
|
||||||
|
|
||||||
|
import { findIndex, filter, first } from "underscore";
|
||||||
|
import { ISelectedPermission } from "../ISpSecurityWebPartProps";
|
||||||
|
import * as React from 'react';
|
||||||
|
import { Label } from 'office-ui-fabric-react/lib/Label';
|
||||||
|
import { Button } from 'office-ui-fabric-react/lib/Button';
|
||||||
|
import { Panel, PanelType } from 'office-ui-fabric-react/lib/Panel';
|
||||||
|
import { Icon } from 'office-ui-fabric-react/lib/Icon';
|
||||||
|
import { IconButton } from 'office-ui-fabric-react/lib/Button';
|
||||||
|
import { DetailsList, IColumn, DetailsListLayoutMode, SelectionMode, Selection } from "office-ui-fabric-react/lib/DetailsList";
|
||||||
|
import { Dropdown, IDropdownOption } from "office-ui-fabric-react/lib/Dropdown";
|
||||||
|
import { CommandBar } from "office-ui-fabric-react/lib/CommandBar";
|
||||||
|
import { SPPermission } from "@microsoft/sp-page-context";
|
||||||
|
import ColorIconSelectorDialog from "./ColorIconSelectorDialog";
|
||||||
|
import { disableBodyScroll } from "@uifabric/utilities";
|
||||||
|
|
||||||
|
export interface ISelectedPemissionPanelProps {
|
||||||
|
isOpen: boolean;
|
||||||
|
onPropertyChange(propertyPath: string, oldValue: any, newValue: any): void;
|
||||||
|
closePanel(): void;
|
||||||
|
|
||||||
|
SelectedPermissions: Array<ISelectedPermission>;
|
||||||
|
}
|
||||||
|
export interface ISelectedPemissionPanelState {
|
||||||
|
|
||||||
|
SelectedPermissions: Array<ISelectedPermission>;
|
||||||
|
CurrentlySelectedPermission?: ISelectedPermission;
|
||||||
|
isColorIconSelecorDialogOpen: boolean;
|
||||||
|
}
|
||||||
|
export default class SelectedPermissionsPanel extends React.Component<ISelectedPemissionPanelProps, ISelectedPemissionPanelState> {
|
||||||
|
private selection: Selection;
|
||||||
|
private columns: IColumn[] = [
|
||||||
|
{
|
||||||
|
key: 'permission',
|
||||||
|
name: 'Permission',
|
||||||
|
fieldName: 'permission',
|
||||||
|
minWidth: 150,
|
||||||
|
maxWidth: 150,
|
||||||
|
isResizable: true,
|
||||||
|
onRender: (item?: any, index?: number, column?: IColumn) => {
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dropdown
|
||||||
|
options={this.getPermissionTypes()}
|
||||||
|
defaultSelectedKey={item.permission}
|
||||||
|
onChange={(event: React.FormEvent<HTMLDivElement>, option?: IDropdownOption, ix?: number) => {
|
||||||
|
var sps = this.state.SelectedPermissions;
|
||||||
|
item.permission = option.text;
|
||||||
|
this.setState((current) => ({ ...current, SelectedPermissions: [...this.state.SelectedPermissions] }));
|
||||||
|
|
||||||
|
}}>
|
||||||
|
</Dropdown>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'freindlyName',
|
||||||
|
name: 'Name in Legend',
|
||||||
|
fieldName: 'freindlyName',
|
||||||
|
minWidth: 150,
|
||||||
|
maxWidth: 150,
|
||||||
|
isResizable: true
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'color',
|
||||||
|
name: 'Display',
|
||||||
|
fieldName: 'color',
|
||||||
|
minWidth: 100,
|
||||||
|
maxWidth: 100,
|
||||||
|
isResizable: true,
|
||||||
|
onRender: (item?: ISelectedPermission, index?: number, column?: IColumn) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Icon iconName={item.iconName} style={{ color: item.color }} />
|
||||||
|
|
||||||
|
<Button onClick={(e) => {
|
||||||
|
this.setState((current) => ({
|
||||||
|
...current,
|
||||||
|
isColorIconSelecorDialogOpen: true,
|
||||||
|
CurrentlySelectedPermission: item
|
||||||
|
}));
|
||||||
|
}}>Edit Permission</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'commands',
|
||||||
|
name: '',
|
||||||
|
fieldName: 'color',
|
||||||
|
minWidth: 50,
|
||||||
|
maxWidth: 50,
|
||||||
|
isResizable: false,
|
||||||
|
onRender: (item?: any, index?: number, column?: IColumn) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<IconButton
|
||||||
|
iconProps={{ iconName: 'Up', }}
|
||||||
|
style={{ display: index === 0 ? "none" : "normal" }}
|
||||||
|
onClick={(e) => {
|
||||||
|
this.moveColumnUp(item);
|
||||||
|
}}>
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
|
<IconButton
|
||||||
|
iconProps={{ iconName: 'Down', }}
|
||||||
|
style={{ display: index === this.state.SelectedPermissions.length - 1 ? "none" : "normal" }}
|
||||||
|
onClick={(e) => {
|
||||||
|
this.moveColumnDown(item);
|
||||||
|
}}>
|
||||||
|
</IconButton>
|
||||||
|
|
||||||
|
<IconButton
|
||||||
|
iconProps={{ iconName: 'Delete', }}
|
||||||
|
onClick={(e) => {
|
||||||
|
this.removeColumn(item);
|
||||||
|
}}>
|
||||||
|
</IconButton>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
];
|
||||||
|
constructor(props: ISelectedPemissionPanelProps) {
|
||||||
|
super(props);
|
||||||
|
this.selection = new Selection({
|
||||||
|
onSelectionChanged: () => console.log("onSelectionChanged...")
|
||||||
|
});
|
||||||
|
this.state = {
|
||||||
|
SelectedPermissions: this.props.SelectedPermissions,
|
||||||
|
isColorIconSelecorDialogOpen: false,
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public getPermissionTypes(): IDropdownOption[] {
|
||||||
|
let perms = new Array<IDropdownOption>();
|
||||||
|
for (const perm in SPPermission) {
|
||||||
|
if (typeof (SPPermission[perm]) === "object") {
|
||||||
|
perms.push({
|
||||||
|
text: perm,
|
||||||
|
key: perm,
|
||||||
|
disabled: findIndex(this.state.SelectedPermissions, (sp: ISelectedPermission) => { return sp.permission == perm; }) !== -1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return perms;
|
||||||
|
}
|
||||||
|
|
||||||
|
// private addColumn(): void {
|
||||||
|
// let unusedPermission = first(filter(this.getPermissionTypes(), (pt) => { return !pt.disabled }));
|
||||||
|
// if (unusedPermission) {
|
||||||
|
|
||||||
|
// const col: ISelectedPermission = {
|
||||||
|
// "permission": unusedPermission.text,
|
||||||
|
// "freindlyName": unusedPermission.text,
|
||||||
|
// color: "FFFFFF",
|
||||||
|
// iconName: "Blocked"
|
||||||
|
// };
|
||||||
|
// var sp = this.state.SelectedPermissions;
|
||||||
|
// sp.push(col);
|
||||||
|
// this.setState((current) => ({ ...current, SelectedPermissions: [...sp] }));
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
private removeColumn(column: ISelectedPermission): void {
|
||||||
|
var sps = filter(this.state.SelectedPermissions, (o: ISelectedPermission) => { return o.permission !== column.permission; });
|
||||||
|
this.setState((current) => ({ ...current, SelectedPermissions: [...sps] }));
|
||||||
|
}
|
||||||
|
private removeAllColumns(): void {
|
||||||
|
this.setState((current) => ({ ...current, SelectedPermissions: [] }));
|
||||||
|
}
|
||||||
|
private moveColumnUp(column: ISelectedPermission): void {
|
||||||
|
|
||||||
|
var sps: ISelectedPermission[] = this.state.SelectedPermissions;
|
||||||
|
const index = findIndex(sps, (sp: ISelectedPermission) => { return sp.permission == column.permission; });
|
||||||
|
if (index != -1) {
|
||||||
|
sps[index] = sps.splice(index - 1, 1, sps[index])[0];
|
||||||
|
this.setState((current) => ({ ...current, SelectedPermissions: [...sps] }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private moveColumnDown(column: ISelectedPermission): void {
|
||||||
|
|
||||||
|
var sps: ISelectedPermission[] = this.state.SelectedPermissions;
|
||||||
|
const index = findIndex(sps, (sp: ISelectedPermission) => { return sp.permission == column.permission; });
|
||||||
|
if (index != -1) {
|
||||||
|
sps[index] = sps.splice(index + 1, 1, sps[index])[0];
|
||||||
|
this.setState((current) => ({ ...current, SelectedPermissions: [...sps] }));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private saveChanges(): void {
|
||||||
|
if (this.props.onPropertyChange) {
|
||||||
|
this.props.onPropertyChange("SelectedPermissions", this.props.SelectedPermissions, this.state.SelectedPermissions);
|
||||||
|
this.onClosePanel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private onOpenPanel(element?: any): void {
|
||||||
|
this.setState((current) => ({ ...current, openPanel: true }));
|
||||||
|
}
|
||||||
|
private onClosePanel(element?: any): void {
|
||||||
|
this.props.closePanel();
|
||||||
|
}
|
||||||
|
public render(): JSX.Element {
|
||||||
|
|
||||||
|
//Renders content
|
||||||
|
return (
|
||||||
|
|
||||||
|
<Panel
|
||||||
|
isOpen={this.props.isOpen} hasCloseButton={true}
|
||||||
|
onDismiss={() => this.onClosePanel()}
|
||||||
|
isLightDismiss={true} type={PanelType.largeFixed}
|
||||||
|
headerText="Select Permissions" >
|
||||||
|
<Label>The grid will display the color of the first match, so list permissions from most restricted to least restricted (i.e. manageLists, then deleteListItems, then viewListItems)</Label>
|
||||||
|
<CommandBar items={[{
|
||||||
|
key: "AddColumns",
|
||||||
|
name: "Add a Permission",
|
||||||
|
icon: "Add",
|
||||||
|
onClick: () => {
|
||||||
|
this.setState((current) => ({
|
||||||
|
...current,
|
||||||
|
isColorIconSelecorDialogOpen: true,
|
||||||
|
CurrentlySelectedPermission: { color: null, freindlyName: null, iconName: null, permission: null }
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "ClearAllColums",
|
||||||
|
name: "Remove All Permissions",
|
||||||
|
canCheck: true,
|
||||||
|
icon: "Delete",
|
||||||
|
onClick: () => {
|
||||||
|
this.removeAllColumns();
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "save",
|
||||||
|
name: "Save",
|
||||||
|
canCheck: true,
|
||||||
|
icon: "Save",
|
||||||
|
onClick: () => {
|
||||||
|
|
||||||
|
this.saveChanges();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
]} />
|
||||||
|
{this.state.isColorIconSelecorDialogOpen &&
|
||||||
|
<ColorIconSelectorDialog
|
||||||
|
isOpen={this.state.isColorIconSelecorDialogOpen}
|
||||||
|
SelectedPermissions={this.state.SelectedPermissions}
|
||||||
|
title={`Edit Icon and color for ${this.state.CurrentlySelectedPermission.permission}`}
|
||||||
|
subText={`Edit Icon and color for ${this.state.CurrentlySelectedPermission.permission}`}
|
||||||
|
currentPerm={this.state.CurrentlySelectedPermission}
|
||||||
|
closePanel={() => {
|
||||||
|
this.setState((current) => ({ ...current, isColorIconSelecorDialogOpen: false }));
|
||||||
|
}}
|
||||||
|
onPermissionChange={(perm: ISelectedPermission) => {
|
||||||
|
//debugger;
|
||||||
|
var sps = this.state.SelectedPermissions;
|
||||||
|
const idx = findIndex(sps, (sp: ISelectedPermission) => { return sp.permission == perm.permission; });
|
||||||
|
if (idx === -1) {
|
||||||
|
sps.push(perm);
|
||||||
|
} else {
|
||||||
|
sps[idx] = perm;
|
||||||
|
}
|
||||||
|
this.setState((current) => ({ ...current, SelectedPermissions: [...sps] }));
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
<DetailsList
|
||||||
|
items={this.state.SelectedPermissions}
|
||||||
|
columns={this.columns}
|
||||||
|
selectionMode={SelectionMode.single}
|
||||||
|
layoutMode={DetailsListLayoutMode.justified}
|
||||||
|
selection={this.selection}
|
||||||
|
/>
|
||||||
|
</Panel>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
|
@ -0,0 +1,47 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.2/MicrosoftTeams.schema.json",
|
||||||
|
"manifestVersion": "1.2",
|
||||||
|
"packageName": "SPSecurity",
|
||||||
|
"id": "41e37f03-2ea8-4f19-b77a-f2121a1e7c45",
|
||||||
|
"version": "0.1",
|
||||||
|
"developer": {
|
||||||
|
"name": "SPFx + Teams Dev",
|
||||||
|
"websiteUrl": "https://products.office.com/en-us/sharepoint/collaboration",
|
||||||
|
"privacyUrl": "https://privacy.microsoft.com/en-us/privacystatement",
|
||||||
|
"termsOfUseUrl": "https://www.microsoft.com/en-us/servicesagreement"
|
||||||
|
},
|
||||||
|
"name": {
|
||||||
|
"short": "SPSecurity"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"short": "Security Grid Display",
|
||||||
|
"full": "Security Grid Display"
|
||||||
|
},
|
||||||
|
"icons": {
|
||||||
|
"outline": "tab20x20.png",
|
||||||
|
"color": "tab96x96.png"
|
||||||
|
},
|
||||||
|
"accentColor": "#004578",
|
||||||
|
"configurableTabs": [
|
||||||
|
{
|
||||||
|
"configurationUrl": "https://{teamSiteDomain}{teamSitePath}/_layouts/15/TeamsLogon.aspx?SPFX=true&dest={teamSitePath}/_layouts/15/teamshostedapp.aspx%3FopenPropertyPane=true%26teams%26componentId=41e37f03-2ea8-4f19-b77a-f2121a1e7c45",
|
||||||
|
"canUpdateConfiguration": true,
|
||||||
|
"scopes": [
|
||||||
|
"team"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"validDomains": [
|
||||||
|
"*.login.microsoftonline.com",
|
||||||
|
"*.sharepoint.com",
|
||||||
|
"*.sharepoint-df.com",
|
||||||
|
"spoppe-a.akamaihd.net",
|
||||||
|
"spoprod-a.akamaihd.net",
|
||||||
|
"resourceseng.blob.core.windows.net",
|
||||||
|
"msft.spoppe.com"
|
||||||
|
],
|
||||||
|
"webApplicationInfo": {
|
||||||
|
"resource": "https://{teamSiteDomain}",
|
||||||
|
"id": "00000003-0000-0ff1-ce00-000000000000"
|
||||||
|
}
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 933 B |
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
|
@ -1,8 +1,21 @@
|
||||||
{
|
{
|
||||||
|
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.3/includes/tsconfig-web.json",
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"lib"
|
||||||
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"outDir": "lib",
|
||||||
|
"inlineSources": false,
|
||||||
|
"strictNullChecks": false,
|
||||||
|
"noUnusedLocals": false,
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"module": "commonjs",
|
"module": "esnext",
|
||||||
"jsx": "react",
|
"jsx": "react",
|
||||||
"declaration": true,
|
"declaration": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
|
|
|
@ -1,3 +1,30 @@
|
||||||
{
|
{
|
||||||
"rulesDirectory": "./config"
|
"extends": "@microsoft/sp-tslint-rules/base-tslint.json",
|
||||||
|
"rules": {
|
||||||
|
"class-name": false,
|
||||||
|
"export-name": false,
|
||||||
|
"forin": false,
|
||||||
|
"label-position": false,
|
||||||
|
"member-access": true,
|
||||||
|
"no-arg": false,
|
||||||
|
"no-console": false,
|
||||||
|
"no-construct": false,
|
||||||
|
"no-duplicate-variable": true,
|
||||||
|
"no-eval": false,
|
||||||
|
"no-function-expression": true,
|
||||||
|
"no-internal-module": true,
|
||||||
|
"no-shadowed-variable": true,
|
||||||
|
"no-switch-case-fall-through": true,
|
||||||
|
"no-unnecessary-semicolons": true,
|
||||||
|
"no-unused-expression": true,
|
||||||
|
"no-use-before-declare": true,
|
||||||
|
"no-with-statement": true,
|
||||||
|
"semicolon": true,
|
||||||
|
"trailing-comma": false,
|
||||||
|
"typedef": false,
|
||||||
|
"typedef-whitespace": false,
|
||||||
|
"use-named-parameter": true,
|
||||||
|
"variable-name": false,
|
||||||
|
"whitespace": false
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Reference in New Issue