Added theme support
This commit is contained in:
parent
e4e1a044b1
commit
a23babceac
|
@ -1,8 +1,12 @@
|
|||
{
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"version": "1.1.1",
|
||||
"isDomainIsolated": false,
|
||||
"isCreatingSolution": false,
|
||||
"packageManager": "npm",
|
||||
"version": "1.10.0",
|
||||
"libraryName": "spsecurity-webpart-3",
|
||||
"libraryId": "788271fb-ee9b-40df-8381-eb3dc70d1982",
|
||||
"environment": "spo"
|
||||
"environment": "spo",
|
||||
"componentType": "webpart"
|
||||
}
|
||||
}
|
|
@ -13,25 +13,27 @@ extensions:
|
|||
- react
|
||||
createdDate: 12/1/2017 12:00:00 AM
|
||||
---
|
||||
# SPFx React Grid
|
||||
# SPFX React Grid
|
||||
|
||||
## 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)
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
|
@ -39,36 +41,45 @@ The user can change alternate between displaying user names and emails selectin
|
|||
|
||||
![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)
|
||||
|
||||
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 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 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.
|
||||
|
||||
Display Settings
|
||||
### Display Settings
|
||||
|
||||
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
|
||||
![List Configuration panel](./src/images/ListConfiguration.PNG)
|
||||
|
||||
List Settings
|
||||
### List Settings
|
||||
|
||||
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 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.
|
||||
|
||||
Select Lists
|
||||
### Select Lists
|
||||
|
||||
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
|
||||
|
||||
![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
|
||||
|
||||
|
@ -101,6 +112,7 @@ Solution|Author(s)
|
|||
|
||||
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.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",
|
||||
"bundles": {
|
||||
"sp-security-bundle": {
|
||||
|
@ -16,4 +16,4 @@
|
|||
"PropertyControlStrings": "./node_modules/@pnp/spfx-property-controls/lib/loc/{locale}.js"
|
||||
},
|
||||
"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"
|
||||
}
|
||||
|
|
|
@ -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/",
|
||||
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
||||
"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": {
|
||||
"includeClientSideAssets": true,
|
||||
"isDomainIsolated": false,
|
||||
"name": "spsecurity-webpart-3-client-side-solution",
|
||||
"id": "788271fb-ee9b-40df-8381-eb3dc70d1982",
|
||||
"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,
|
||||
"initialPage": "https://localhost:5432/workbench",
|
||||
"https": true,
|
||||
"api": {
|
||||
"port": 5432,
|
||||
"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 -->"
|
||||
}
|
||||
|
|
|
@ -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-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.initialize(gulp);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,39 +1,49 @@
|
|||
{
|
||||
"main": "lib/index.js",
|
||||
"name": "spsecurity-webpart-3",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "16.8.8"
|
||||
},
|
||||
"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/logging": "1.3.3",
|
||||
"@pnp/odata": "1.3.3",
|
||||
"@pnp/sp": "1.3.3",
|
||||
"@pnp/spfx-property-controls": "1.0.0",
|
||||
"@types/react": "15.0.38",
|
||||
"@types/react-addons-shallow-compare": "0.14.17",
|
||||
"@types/react-addons-test-utils": "0.14.15",
|
||||
"@types/react-addons-update": "0.14.14",
|
||||
"@types/react-dom": "0.14.18",
|
||||
"@types/webpack-env": ">=1.12.1 <1.14.0",
|
||||
"lodash": "^4.17.15",
|
||||
"office-ui-fabric-react": "^4.21.2",
|
||||
"react": "15.4.2",
|
||||
"react-dom": "15.4.2"
|
||||
"@types/es6-promise": "0.0.33",
|
||||
"@types/react": "16.8.8",
|
||||
"@types/react-dom": "16.8.3",
|
||||
"@types/webpack-env": "1.13.1",
|
||||
"lodash": "^4.17.4",
|
||||
"natives": "^1.1.6",
|
||||
"office-ui-fabric-react": "6.189.2",
|
||||
"react": "16.8.5",
|
||||
"react-dom": "16.8.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/sp-build-web": "~1.4.1",
|
||||
"@microsoft/sp-module-interfaces": "~1.4.1",
|
||||
"@microsoft/sp-webpart-workbench": "~1.4.1",
|
||||
"@types/chai": ">=3.4.34 <3.6.0",
|
||||
"@types/mocha": ">=2.2.33 <2.6.0",
|
||||
"gulp": "~3.9.1"
|
||||
"@microsoft/rush-stack-compiler-3.2": "0.6.8",
|
||||
"@microsoft/rush-stack-compiler-3.3": "0.3.5",
|
||||
"@microsoft/sp-build-web": "1.10.0",
|
||||
"@microsoft/sp-core-library": "1.10.0",
|
||||
"@microsoft/sp-lodash-subset": "1.10.0",
|
||||
"@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": {
|
||||
"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 { 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 {
|
||||
id: number;
|
||||
|
@ -69,6 +69,7 @@ export class SPSecurityInfo {
|
|||
this.siteUsers = new Array<SPSiteUser>();
|
||||
this.lists = new Array<SPList>();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -110,7 +111,20 @@ export class SPRoleAssignment {
|
|||
|
||||
}
|
||||
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) {
|
||||
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);
|
||||
for (const permission of permissions) {
|
||||
if (
|
||||
|
@ -193,7 +207,7 @@ export class Helpers {
|
|||
}
|
||||
return selectedRoleAssignments;
|
||||
} catch (exception) {
|
||||
debugger;
|
||||
//debugger;
|
||||
console.error(exception);
|
||||
}
|
||||
|
||||
|
@ -262,7 +276,7 @@ export default class SPSecurityService {
|
|||
for (let roleAssignmentObject of listItem.RoleAssignments) {
|
||||
|
||||
let roleAssignment: SPRoleAssignment = {
|
||||
roleDefinitionIds: roleAssignmentObject.RoleDefinitionBindings.map((rdb) => { return rdb.Id; }),
|
||||
roleDefinitionIds: roleAssignmentObject.RoleDefinitionBindings.map((rdb) => { return rdb.Id; }),
|
||||
principalId: roleAssignmentObject.PrincipalId
|
||||
};
|
||||
// if (roleAssignmentObject.Member.UserId) {
|
||||
|
@ -291,26 +305,27 @@ export default class SPSecurityService {
|
|||
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",
|
||||
GraphHttpClient.configurations.v1).then((response) => {
|
||||
response.json().then((data) => {
|
||||
debugger;
|
||||
});
|
||||
}).catch((err) => {
|
||||
});
|
||||
}
|
||||
// return aadHttpClient.get("v1.0/groups?$filter=displayName eq '" + groupName + "'&$expand=members",
|
||||
// AadHttpClient.configurations.v1).then((response) => {
|
||||
// response.json().then((data) => {
|
||||
// debugger;
|
||||
// });
|
||||
// }).catch((err) => {
|
||||
// console.log(err);
|
||||
// });
|
||||
// }
|
||||
/// 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 batch: any = sp.createBatch();
|
||||
let errors: Array<string> = [];
|
||||
|
||||
sp.web.siteUsers
|
||||
.inBatch(batch).get().then((response) => {
|
||||
sp.web.siteUsers.inBatch(batch).get()
|
||||
.then((response) => {
|
||||
console.table(response);
|
||||
securityInfo.siteUsers = response.map((u) => {
|
||||
|
||||
let user: SPSiteUser = new SPSiteUser();
|
||||
user.isSelected = true;
|
||||
user.id = u.Id;
|
||||
|
@ -325,9 +340,14 @@ export default class SPSecurityService {
|
|||
return user;
|
||||
});
|
||||
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")
|
||||
.inBatch(batch).get().then((response) => {
|
||||
sp.web.siteGroups.filter(`Title ne 'Limited Access System Group'`).expand("Users").select("Title", "Id", "IsHiddenInUI", "IsShareByEmailGuestUse", "IsSiteAdmin", "IsSiteAdmin")
|
||||
.inBatch(batch).get()
|
||||
.then((response) => {
|
||||
let AdGroupPromises: Array<Promise<any>> = [];
|
||||
// if group contains an ad group(PrincipalType=4) expand it
|
||||
securityInfo.siteGroups = response.map((grp) => {
|
||||
|
@ -365,23 +385,33 @@ export default class SPSecurityService {
|
|||
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) => {
|
||||
securityInfo.roleDefinitions = response.map((rd) => {
|
||||
sp.web.roleDefinitions.expand("BasePermissions").inBatch(batch).get()
|
||||
.then((response) => {
|
||||
securityInfo.roleDefinitions = response.map((rd) => {
|
||||
|
||||
const bp: SPBasePermissions = new SPBasePermissions(rd.BasePermissions.High, rd.BasePermissions.Low);
|
||||
const roleDefinition: SPRoleDefinition = new SPRoleDefinition(
|
||||
parseInt(rd.Id, 10),
|
||||
bp,
|
||||
rd.Description,
|
||||
rd.Hidden,
|
||||
rd.Name);
|
||||
const bp: SPBasePermissions = new SPBasePermissions(rd.BasePermissions.High, rd.BasePermissions.Low);
|
||||
const roleDefinition: SPRoleDefinition = new SPRoleDefinition(
|
||||
parseInt(rd.Id, 10),
|
||||
bp,
|
||||
rd.Description,
|
||||
rd.Hidden,
|
||||
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[] = [];
|
||||
if (!showHiddenLists) {
|
||||
filters.push("Hidden eq false");
|
||||
|
@ -392,10 +422,9 @@ export default class SPSecurityService {
|
|||
let filter: string = filters.join(" and ");
|
||||
sp.web.lists
|
||||
.expand("RootFolder", "RoleAssignments", "RoleAssignments/RoleDefinitionBindings", "RoleAssignments/Member",
|
||||
"RoleAssignments/Member/Users", "RoleAssignments/Member/Groups", "RoleAssignments/Member/UserId")
|
||||
.filter(filter)
|
||||
.inBatch(batch).get().then((response) => {
|
||||
|
||||
"RoleAssignments/Member/Users", "RoleAssignments/Member/Groups", "RoleAssignments/Member/UserId")
|
||||
.filter(filter).inBatch(batch).get()
|
||||
.then((response) => {
|
||||
securityInfo.lists = response.map((listObject) => {
|
||||
let mylist: SPList = new SPList();
|
||||
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;
|
||||
});
|
||||
|
||||
}).catch((error) => {
|
||||
//debugger;
|
||||
errors.push(`There was an error fetching lists -- ${error.message} `);
|
||||
//error fetching lists
|
||||
throw error;
|
||||
|
||||
});
|
||||
return batch.execute().then(() => {
|
||||
return securityInfo;
|
||||
}).catch((error) => {
|
||||
//debugger;
|
||||
// error in batch
|
||||
throw errors;
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,20 +1,29 @@
|
|||
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 {
|
||||
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;
|
||||
showCatalogs:boolean;
|
||||
letUserSelectPermission:boolean;
|
||||
letUserSelectUsers:boolean;
|
||||
letUserSelectLists:boolean;
|
||||
includeAdminSelectedLists:boolean; // true to inlude them, false to excluder
|
||||
adminSelectedLists:string[];
|
||||
listTitleColumnWidth:number;
|
||||
showEmail:boolean; //0 show name, 1 show email
|
||||
showSecurityGroups:boolean; // show PrincipalType=4
|
||||
showUsers:boolean; // show PrincipalType=1
|
||||
|
||||
showCatalogs: boolean;
|
||||
letUserSelectPermission: boolean;
|
||||
letUserSelectUsers: boolean;
|
||||
letUserSelectLists: boolean;
|
||||
includeAdminSelectedLists: boolean; // true to inlude them, false to excluder
|
||||
adminSelectedLists: string[];
|
||||
listTitleColumnWidth: number;
|
||||
showEmail: boolean; //0 show name, 1 show email
|
||||
showSecurityGroups: boolean; // show PrincipalType=4
|
||||
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",
|
||||
"alias": "SpSecurityWebPart",
|
||||
"componentType": "WebPart",
|
||||
|
@ -8,13 +8,17 @@
|
|||
/**
|
||||
* This property should only be set to true if it is certain that the webpart does not
|
||||
* allow arbitrary scripts to be called
|
||||
*/
|
||||
"safeWithCustomScriptDisabled": false,
|
||||
*
|
||||
"requiresCustomScript": true,
|
||||
*/
|
||||
"supportedHosts": [
|
||||
"SharePointWebPart"
|
||||
],
|
||||
"preconfiguredEntries": [
|
||||
{
|
||||
"groupId": "41e37f03-2ea8-4f19-b77a-f2121a1e7c45",
|
||||
"group": {
|
||||
"default": "Under Development"
|
||||
"default": "Other"
|
||||
},
|
||||
"title": {
|
||||
"default": "SPSecurity"
|
||||
|
@ -33,7 +37,29 @@
|
|||
"includeAdminSelectedLists": false,
|
||||
"listTitleColumnWidth": 120,
|
||||
"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 { SPPermission } from "@microsoft/sp-page-context";
|
||||
import { PropertyFieldListPicker, PropertyFieldListPickerOrderBy } from '@pnp/spfx-property-controls/lib/PropertyFieldListPicker';
|
||||
import {
|
||||
BaseClientSideWebPart,
|
||||
IPropertyPaneConfiguration,
|
||||
PropertyPaneTextField,
|
||||
PropertyPaneDropdown, IPropertyPaneDropdownOption,
|
||||
PropertyPaneCheckbox,
|
||||
PropertyPaneToggle
|
||||
} from "@microsoft/sp-webpart-base";
|
||||
import {sp} from "@pnp/sp";
|
||||
import { PropertyFieldSelectedPermissions, IPropertyFieldSelectedPermissionsProps } from "./containers/PropertyFieldSelectedPermissions";
|
||||
import { sp } from "@pnp/sp";
|
||||
import * as strings from "spSecurityStrings";
|
||||
import SpSecurity from "./components/SpSecurity";
|
||||
import { ISpSecurityProps } from "./components/ISpSecurityProps";
|
||||
|
||||
import { ISpSecurityWebPartProps } from "./ISpSecurityWebPartProps";
|
||||
import { PropertyPaneSlider } from "@microsoft/sp-webpart-base/lib/propertyPane/propertyPaneFields/propertyPaneSlider/PropertyPaneSlider";
|
||||
import PropertyPane from "@microsoft/sp-webpart-base/lib/propertyPane/propertyPane/PropertyPane";
|
||||
import { BaseClientSideWebPart } from "@microsoft/sp-webpart-base";
|
||||
import {
|
||||
IPropertyPaneConfiguration, PropertyPaneCheckbox,
|
||||
IPropertyPaneDropdownOption, PropertyPaneDropdown, PropertyPaneTextField,
|
||||
PropertyPaneToggle, PropertyPaneSlider
|
||||
} from "@microsoft/sp-property-pane";
|
||||
|
||||
export default class SpSecurityWebPart extends BaseClientSideWebPart<ISpSecurityWebPartProps> {
|
||||
public onInit(): Promise<void> {
|
||||
|
@ -31,15 +28,18 @@ export default class SpSecurityWebPart extends BaseClientSideWebPart<ISpSecurity
|
|||
});
|
||||
});
|
||||
}
|
||||
|
||||
public render(): void {
|
||||
|
||||
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,
|
||||
showCatalogs: this.properties.showCatalogs,
|
||||
showEmail: this.properties.showEmail,
|
||||
showSecurityGroups: this.properties.showSecurityGroups,
|
||||
showUsers: this.properties.showUsers,
|
||||
showOnlyUsersWithPermission: this.properties.showOnlyUsersWithPermission,
|
||||
letUserSelectPermission: this.properties.letUserSelectPermission,
|
||||
letUserSelectUsers: this.properties.letUserSelectUsers,
|
||||
letUserSelectLists: this.properties.letUserSelectLists,
|
||||
|
@ -48,8 +48,8 @@ export default class SpSecurityWebPart extends BaseClientSideWebPart<ISpSecurity
|
|||
listTitleColumnWidth: this.properties.listTitleColumnWidth,
|
||||
users: this.properties.users,
|
||||
getPermissionTypes: this.getPermissionTypes,
|
||||
graphHttpClient: this.context.graphHttpClient,
|
||||
domElement : this.domElement
|
||||
aadHttpClient: null,//this.context.aadHttpClient,
|
||||
domElement: this.domElement
|
||||
|
||||
};
|
||||
const element: React.ReactElement<ISpSecurityProps> = React.createElement(
|
||||
|
@ -75,21 +75,41 @@ export default class SpSecurityWebPart extends BaseClientSideWebPart<ISpSecurity
|
|||
}
|
||||
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 {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
header: {
|
||||
description: "Configuration"
|
||||
description: "Permission Configuration"
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
groupName: "Permission Settings",
|
||||
groupFields: [
|
||||
|
||||
PropertyPaneDropdown("permission", {
|
||||
label: "Permission Type",
|
||||
options: this.getPermissionTypes()
|
||||
PropertyFieldSelectedPermissions("SelectedPermissions", {
|
||||
label: "Selected Permissions and Colors",
|
||||
onPropertyChange: this.onPropertyChange.bind(this),
|
||||
|
||||
getSelectedPermissions: () => {
|
||||
return this.properties.selectedPermissions || [];
|
||||
},
|
||||
}),
|
||||
PropertyPaneCheckbox("letUserSelectPermission", {
|
||||
text: "Let user select Permission"
|
||||
|
@ -112,7 +132,11 @@ export default class SpSecurityWebPart extends BaseClientSideWebPart<ISpSecurity
|
|||
PropertyPaneCheckbox("showUsers", {
|
||||
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", {
|
||||
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: {
|
||||
description: "Configure Lists"
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
import { SPSiteUser } from "../../SPSecurityService";
|
||||
import { SPPermission } from "@microsoft/sp-page-context";
|
||||
import {IPropertyPaneDropdownOption} from "@microsoft/sp-webpart-base";
|
||||
import { GraphHttpClient } from "@microsoft/sp-http";
|
||||
import { } from "@microsoft/sp-webpart-base";
|
||||
import { IPropertyPaneDropdownOption, PropertyPaneDropdown } from "@microsoft/sp-property-pane";
|
||||
import { AadHttpClient } from "@microsoft/sp-http";
|
||||
import {ISelectedPermission} from "../ISpSecurityWebPartProps";
|
||||
export interface ISpSecurityProps {
|
||||
users: SPSiteUser[];
|
||||
permission: string;
|
||||
//permission: string;
|
||||
selectedPermissions:ISelectedPermission[];
|
||||
showHiddenLists: boolean;
|
||||
showCatalogs:boolean;
|
||||
getPermissionTypes:()=> IPropertyPaneDropdownOption[];
|
||||
graphHttpClient: GraphHttpClient;
|
||||
aadHttpClient: AadHttpClient;
|
||||
letUserSelectPermission:boolean;
|
||||
letUserSelectUsers:boolean;
|
||||
letUserSelectLists:boolean;
|
||||
|
@ -18,6 +21,7 @@ export interface ISpSecurityProps {
|
|||
showEmail:boolean; //0 show name, 1 show email
|
||||
showSecurityGroups:boolean; // show PrincipalType=4
|
||||
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
|
||||
|
||||
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
import { SPSecurityInfo } from "../../SPSecurityService";
|
||||
import { ISelectedPermission } from "../ISpSecurityWebPartProps";
|
||||
export interface ISpSecurityState {
|
||||
securityInfo: SPSecurityInfo;
|
||||
permission: string;
|
||||
showUserPanel:boolean;
|
||||
showListPanel:boolean;
|
||||
showEmail:boolean; //0 show name, 1 show email
|
||||
securityInfoLoaded:boolean;
|
||||
// permission: string;
|
||||
selectedPermissions: ISelectedPermission[];
|
||||
showUserPanel: boolean;
|
||||
showListPanel: 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 {
|
||||
}
|
||||
.themecolor {
|
||||
color: $ms-color-themePrimary;
|
||||
color: $ms-color-themeDarkAlt;
|
||||
}
|
||||
|
||||
.nonbrandeddocumentcolor {
|
||||
color: "#00FF00";
|
||||
}
|
||||
|
@ -36,7 +37,15 @@
|
|||
width: 40px !important;
|
||||
}
|
||||
|
||||
.itemTitle {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
: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 { ISpSecurityProps } from "./ISpSecurityProps";
|
||||
import { ISpSecurityState } from "./ISpSecurityState";
|
||||
|
||||
import { ILegendProps, Legend } from "./Legend";
|
||||
import SPSecurityService from "../../SPSecurityService";
|
||||
import { SPListItem, SPList, SPSiteUser, Helpers } from "../../SPSecurityService";
|
||||
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 { Checkbox } from 'office-ui-fabric-react/lib/Checkbox';
|
||||
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 { IContextualMenuItem, ContextualMenuItemType } from "office-ui-fabric-react/lib/ContextualMenu";
|
||||
|
||||
import { ISelectedPermission } from "../ISpSecurityWebPartProps";
|
||||
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 {
|
||||
Environment,
|
||||
EnvironmentType
|
||||
} from '@microsoft/sp-core-library';
|
||||
/* tslint:disable */
|
||||
|
||||
export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSecurityState> {
|
||||
private svc: SPSecurityService = new SPSecurityService("ss");
|
||||
private userSelection = new Selection();
|
||||
|
@ -31,11 +32,14 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
|||
super(props);
|
||||
this.state = {
|
||||
securityInfo: { siteUsers: [], siteGroups: [], roleDefinitions: [], lists: [] },
|
||||
permission: this.props.permission,
|
||||
//permission: this.props.permission,
|
||||
selectedPermissions: this.props.selectedPermissions,
|
||||
showUserPanel: false,
|
||||
showListPanel: false,
|
||||
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 = {
|
||||
securityInfo: response,
|
||||
permission: this.props.permission,
|
||||
// permission: this.props.permission,
|
||||
selectedPermissions: this.props.selectedPermissions ? this.props.selectedPermissions : [],
|
||||
showUserPanel: false,
|
||||
showListPanel: false,
|
||||
showPermissionsPanel: false,
|
||||
showEmail: this.props.showEmail,
|
||||
securityInfoLoaded: true
|
||||
securityInfoLoaded: true,
|
||||
errors:[]
|
||||
|
||||
};
|
||||
// inlclude\exclude lists selected in property pane
|
||||
//debugger;
|
||||
state.securityInfo.lists = state.securityInfo.lists.filter((list) => {
|
||||
if (this.props.includeAdminSelectedLists) { // include the lists
|
||||
|
||||
|
@ -96,8 +115,9 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
|||
}
|
||||
});
|
||||
this.setState(state);
|
||||
}).catch((err) => {
|
||||
debugger;
|
||||
}).catch((errors:Array<string>) => {
|
||||
this.setState((current)=>({...current,errors:errors,securityInfoLoaded:true}))
|
||||
//debugger;
|
||||
});
|
||||
}
|
||||
public expandList(item: any): any {
|
||||
|
@ -135,8 +155,10 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
|||
item.isFetched = true;
|
||||
this.setState(this.state);
|
||||
|
||||
}).catch((err) => {
|
||||
debugger;
|
||||
}).catch((error) => {
|
||||
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 {
|
||||
let extension = item.title.split('.').pop();
|
||||
let classname = "ms-u-smOffset" + (item.level);
|
||||
if (this.validBrandIcons.indexOf(" " + extension + " ") !== -1) {
|
||||
classname += " ms-Icon ms-BrandIcon--" + extension + " ms-BrandIcon--icon16 ";
|
||||
}
|
||||
else {
|
||||
classname += " ms-Icon ms-Icon--TextDocument " + styles.themecolor;
|
||||
}
|
||||
return (
|
||||
<div>
|
||||
const extension = item.title.split('.').pop();
|
||||
const isValidExtension: boolean = (this.validBrandIcons.indexOf(" " + extension + " ") !== -1);
|
||||
const classname = css("ms-u-smOffset" + (item.level), isValidExtension ?
|
||||
`ms-Icon ms-BrandIcon--${extension} ms-BrandIcon--icon16`:
|
||||
`ms-Icon ms-Icon--TextDocument ${styles.themecolor}`);
|
||||
|
||||
return (
|
||||
<div className={styles.itemTitle} >
|
||||
<div className={classname} />
|
||||
<span > {item.title}</span>
|
||||
<span> {item.title}</span>
|
||||
</div>);
|
||||
}
|
||||
public renderListTitle(item?: any, index?: number, column?: IColumn): any {
|
||||
|
||||
let classname = " ms-Icon ";
|
||||
if (item.itemCount > 0) {
|
||||
classname += " ms-Icon ms-Icon--FabricFormLibrary " + styles.themecolor;
|
||||
} else {
|
||||
classname += " ms-Icon ms-Icon--FabricFolder ";
|
||||
}
|
||||
const classname = css("ms-Icon", styles.themecolor, item.itemCount > 0 ?
|
||||
'ms-Icon ms-Icon--FabricFormLibrary':
|
||||
'ms-Icon ms-Icon--FabricFolder');
|
||||
|
||||
return (
|
||||
<div onClick={(e) => {
|
||||
<div className={styles.itemTitle} onClick={(e) => {
|
||||
//debugger;
|
||||
this.expandCollapseList(item);
|
||||
}}>
|
||||
<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 {
|
||||
let classname = "ms-u-smOffset" + (item.level);
|
||||
if (item.itemCount > 0) {
|
||||
classname += " ms-Icon ms-Icon--FabricFormLibrary " + styles.themecolor;
|
||||
} else {
|
||||
classname += " ms-Icon ms-Icon--FabricFolder ";
|
||||
}
|
||||
const classname = css("ms-u-smOffset" + (item.level),styles.themecolor, item.itemCount > 0 ?
|
||||
'ms-Icon ms-Icon--FabricFormLibrary':
|
||||
'ms-Icon ms-Icon--FabricFolder');
|
||||
|
||||
return (
|
||||
<div onClick={(e) => {
|
||||
<div className={styles.itemTitle} onClick={(e) => {
|
||||
this.expandCollapseList(item);
|
||||
}}>
|
||||
<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 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 {
|
||||
public renderUserItem(item: any, index: number, column: IColumn,effectivePermissions:ISelectedPermission[]): any {
|
||||
|
||||
let user: SPSiteUser = find(this.state.securityInfo.siteUsers, (su) => {
|
||||
return su.id.toString() === column.key;
|
||||
});
|
||||
if (Helpers.doesUserHavePermission(item, user, SPPermission[this.state.permission],
|
||||
this.state.securityInfo.roleDefinitions, this.state.securityInfo.siteGroups)) {
|
||||
return (
|
||||
<Icon iconName="CircleFill" onClick={(e) => {
|
||||
this.expandCollapseList(item);
|
||||
}} />
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Icon iconName="LocationCircle" onClick={(e) => {
|
||||
this.expandCollapseList(item);
|
||||
}} />
|
||||
);
|
||||
// spin througg the selected permsiisopns and for the first hit, display that color. No Hit, then display empty
|
||||
|
||||
for (let selectedPermission of effectivePermissions ? effectivePermissions : []) {
|
||||
if (Helpers.doesUserHavePermission(item, user, SPPermission[selectedPermission.permission],
|
||||
this.state.securityInfo.roleDefinitions, this.state.securityInfo.siteGroups)) {
|
||||
return (
|
||||
<Icon iconName={selectedPermission.iconName} style={{ color: selectedPermission.color }} 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 {
|
||||
|
||||
|
@ -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) {
|
||||
if (user.isSelected) {
|
||||
if (
|
||||
|
@ -306,15 +298,20 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
|||
||
|
||||
(user.principalType === 4 && this.props.showSecurityGroups)
|
||||
)
|
||||
columns.push({
|
||||
key: user.id.toString(),
|
||||
name: this.state.showEmail ? user.upn : user.name,
|
||||
fieldName: "",
|
||||
minWidth: 20,
|
||||
maxWidth: 20,
|
||||
onRender: this.renderUserItem,
|
||||
headerClassName: styles.rotatedColumnHeader,
|
||||
});
|
||||
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))
|
||||
columns.push({
|
||||
key: user.id.toString(),
|
||||
name: this.state.showEmail ? user.upn : user.name,
|
||||
fieldName: "",
|
||||
minWidth: 20,
|
||||
maxWidth: 20,
|
||||
onRender: (item?: any, index?: number, column?: IColumn)=>{
|
||||
//debugger;
|
||||
return this.renderUserItem(item,index,column,effectivePermissions);
|
||||
},
|
||||
headerClassName: styles.rotatedColumnHeader,
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
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> {
|
||||
if (!this.state.securityInfoLoaded) {
|
||||
return (
|
||||
|
@ -372,7 +379,6 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
|||
|
||||
);
|
||||
}
|
||||
debugger;
|
||||
let userPanelCommands: IContextualMenuItem[] = [];
|
||||
userPanelCommands.push({
|
||||
icon: "BoxAdditionSolid",
|
||||
|
@ -380,11 +386,9 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
|||
name: "Add All Users",
|
||||
itemType: ContextualMenuItemType.Normal,
|
||||
onClick: (event, item) => {
|
||||
|
||||
for (let item of this.state.securityInfo.siteUsers) {
|
||||
item.isSelected = true;
|
||||
}
|
||||
|
||||
this.setState(this.state);
|
||||
}
|
||||
});
|
||||
|
@ -434,22 +438,17 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
|||
});
|
||||
let commands: IContextualMenuItem[] = [];
|
||||
if (this.props.letUserSelectPermission) {
|
||||
commands.push({
|
||||
title: "Permission",
|
||||
name: "Permission:",
|
||||
key:
|
||||
"permissionlabel"
|
||||
|
||||
})
|
||||
commands.push({
|
||||
icon: "AzureKeyVault",
|
||||
key: "SecurityLevel",
|
||||
title: "Permission",
|
||||
label: "sss",
|
||||
name: this.state.permission ? this.state.permission : "Select Permission",
|
||||
key: "SecurityLevel2",
|
||||
name: "Permission",
|
||||
itemType: ContextualMenuItemType.Normal,
|
||||
items: this.getPermissionLevels()
|
||||
});
|
||||
onClick: (event, item) => {
|
||||
this.setState((current) => ({ ...current, showPermissionsPanel: !current.showPermissionsPanel }));
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
if (this.props.letUserSelectUsers) {
|
||||
commands.push({
|
||||
|
@ -480,26 +479,24 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
|||
title: "DisplayMode",
|
||||
name: this.state.showEmail ? "Show Email" : "Show Name",
|
||||
itemType: ContextualMenuItemType.Normal,
|
||||
items: [{
|
||||
key: "ShowName",
|
||||
name: "Show Name",
|
||||
onClick: (event, item) => {
|
||||
debugger;
|
||||
this.setState((current) => ({ ...current, showEmail: false }));
|
||||
}
|
||||
|
||||
},
|
||||
{
|
||||
key: "ShowEmail",
|
||||
name: "Show Email",
|
||||
onClick: (event, item) => {
|
||||
debugger;
|
||||
this.setState((current) => ({ ...current, showEmail: true }));
|
||||
}
|
||||
|
||||
}]
|
||||
subMenuProps: {
|
||||
items: [{
|
||||
key: "ShowName",
|
||||
name: "Show Name",
|
||||
onClick: (event, item) => {
|
||||
this.setState((current) => ({ ...current, showEmail: false }));
|
||||
}
|
||||
},
|
||||
{
|
||||
key: "ShowEmail",
|
||||
name: "Show Email",
|
||||
onClick: (event, item) => {
|
||||
this.setState((current) => ({ ...current, showEmail: true }));
|
||||
}
|
||||
}]
|
||||
}
|
||||
});
|
||||
|
||||
let effectivePermissions=this.state.selectedPermissions.filter((sp)=>{ return sp.isChecked;})
|
||||
let columns: Array<IColumn> = [
|
||||
{
|
||||
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
|
||||
},
|
||||
];
|
||||
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) => {
|
||||
|
@ -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 (
|
||||
<div >
|
||||
<ul>{errorMessages}</ul>
|
||||
<CommandBar
|
||||
items={commands}
|
||||
/>
|
||||
<br />
|
||||
<Legend
|
||||
selectedPermissions={this.state.selectedPermissions}
|
||||
checkUncheckPermission={(e) => {
|
||||
//debugger;
|
||||
this.checkUncheckPermission(e);
|
||||
|
||||
}
|
||||
}
|
||||
/>
|
||||
<DetailsList
|
||||
items={displayItems}
|
||||
columns={displayColumns}
|
||||
selectionMode={SelectionMode.none}
|
||||
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
|
||||
isBlocking={false}
|
||||
isOpen={this.state.showUserPanel}
|
||||
|
@ -561,6 +590,7 @@ export default class SpSecurity extends React.Component<ISpSecurityProps, ISpSec
|
|||
headerText='Select Lists'
|
||||
closeButtonAriaLabel='Close'>
|
||||
<CommandBar items={listPanelCommands} />
|
||||
|
||||
<DetailsList
|
||||
|
||||
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": {
|
||||
"moduleResolution": "node",
|
||||
"outDir": "lib",
|
||||
"inlineSources": false,
|
||||
"strictNullChecks": false,
|
||||
"noUnusedLocals": false,
|
||||
"target": "es5",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "commonjs",
|
||||
"module": "esnext",
|
||||
"jsx": "react",
|
||||
"declaration": 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