Merge pull request #1950 from russgove/main

This commit is contained in:
Hugo Bernier 2021-07-11 00:01:59 -04:00 committed by GitHub
commit 24fc7f0a7f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
56 changed files with 21924 additions and 1 deletions

View File

@ -0,0 +1,25 @@
# EditorConfig helps developers define and maintain consistent
# coding styles between different editors and IDEs
# editorconfig.org
root = true
[*]
# change these settings to your own preference
indent_style = space
indent_size = 2
# we recommend you to keep these unchanged
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
[{package,bower}.json]
indent_style = space
indent_size = 2

View File

@ -0,0 +1,32 @@
# Logs
logs
*.log
npm-debug.log*
# Dependency directories
node_modules
# Build generated files
dist
lib
solution
temp
*.sppkg
# Coverage directory used by tools like istanbul
coverage
# OSX
.DS_Store
# Visual Studio files
.ntvs_analysis.dat
.vs
bin
obj
# Resx Generated Code
*.resx.ts
# Styles Generated Code
*.scss.ts

View File

@ -0,0 +1,12 @@
{
"@microsoft/generator-sharepoint": {
"isCreatingSolution": false,
"environment": "spo",
"version": "1.10.0",
"libraryName": "r-fx-portal",
"libraryId": "955d006f-7cc7-461f-8c5d-29593aebac61",
"packageManager": "npm",
"isDomainIsolated": false,
"componentType": "webpart"
}
}

View File

@ -0,0 +1,148 @@
# Private Library/Folder Manager
## Summary
This sample provides a webpart that can be used to manage Document Libraries with Secured Subfolders. The use case this was developed for is a Request for Proposal site. A Document library is created for each RFP and subfolders are created within that Library for each external supplier invited to participate in that RFP.
The application manages all the security groups set up for the various libraries and folders so that suppliers only see RFP's they were invited to participate in and only thier folder in those libraries. General documents for the RFP that should be seen by everyone participating in the RFP can be put in the root folder of the library. General terms and conditions that everyone should see can be put at the root folder of the site.
![mainpanel](assets/HomeScreen.png "Main Screen")
![AddingAlibrary](assets/AddALibrary.png "Add A library")
![ManagingFolders](assets/ManageFolders.PNG "Manage Folders")
![AddingAfolder](assets/AddAFolder.png "Add a folder")
![Configuration](assets/Configuration.PNG "Configuration")
## Compatibility
![SPFx 1.10.0](https://img.shields.io/badge/SPFx-1.10.0-green.svg)
![Node.js LTS 8.x | LTS 10.x](https://img.shields.io/badge/Node.js-LTS%208.x%20%7C%20LTS%2010.x-green.svg)
![SharePoint Online](https://img.shields.io/badge/SharePoint-Online-yellow.svg)
![Teams N/A: Untested with Microsoft Teams](https://img.shields.io/badge/Teams-N%2FA-lightgrey.svg "Untested with Microsoft Teams")
![Workbench Hosted: Does not work with local workbench](https://img.shields.io/badge/Workbench-Hosted-yellow.svg "Does not work with local workbench")
## Applies to
* [SharePoint Framework](https://docs.microsoft.com/sharepoint/dev/spfx/sharepoint-framework-overview)
* [Microsoft 365 tenant](https://docs.microsoft.com/sharepoint/dev/spfx/set-up-your-development-environment)
## Solution
Solution|Author(s)
--------|---------
react Private Folder Manager | [Russell Gove](https://github.com/russgove) ([@russgove](https://twitter.com/russgove))
## Version history
Version|Date|Comments
-------|----|--------
1.0|July 2, 2021|Initial release
## Prerequisites
## Minimal Path to Awesome
Build this solution and add it to your app catalog (tenant or site).
Create a new Team Site (Without and Office 365 Group) or Communications site. The site must be configured to allow sharing with any external parties you want to invite to the site.
Install this solution on the site
Create two Lists to hold the List of RFX's and the list of RFX Folders.
The lists must have the schemas below (using site content types is not needed.)
The RFX List:
![rfx](assets/RFX.PNG "RFX")
(The title was renamed to RFX Number)
The RFX Folder List
![rfxfolders](assets/RFXFolders.PNG "RFXFolders")
(The RFx column is a lookup to the Title/RFX Number in the RFx list)
The scripts folder contains a site script (rfx.json) that can be used to create these lists.
The Powershell Script AddLists.ps1 in the same folder can be run to create a site design that creates these lists.
After creating the lists create a new site page and add the Request Maintenance webpart to it. (Break inheritance on the page and ensure only site members or owners have access to it!)
The webpart configuration is below:
![Configuration](assets/Configuration.PNG "Configuration")
The settings are :
* RFX List - the title of the RFX list created above. For each new RFX library created this list will contain the library Name, A closing date (just informational for now, but we could set up a workflow to break access on this date), a contract specialist (the person who create the library and owns it), and the ID's of the Libraries Owner, members and Visitors group. When a new library is added a separate Owners member and visitors group is created just for that library. The person creating the library is added to the Libraries Owner group and the Library Owners group becomes the owner of the Library Members and Visitors Groups, as well as any Folder-level groups within the library.
* RFX Folders List - The title of the RFX Folders list created above. Whenever a new folder is added to a library using the webpart a new entry will be created in this list containing the RFX Name (a lookup to the RFX list), The FOlder Name, and the ID of the folder Members and Visitors groups. Whenever a new folder is created Members and visitors groups are created just for that folder. The Library Owners group of the library containing the folder is also of the Folder Members and Visitors groups.
* Archive Library - The name of a standard document library that can be used to Archive RFX libraries after they are done. If no library name is entered, the Ardchive button will not be shown. When a library is Archived, it is moved to a subfolder in the Archive Library and ALL securiy groups associated with that RFX Library are deleted.
* Permission for library members on Site - The Permission Library members group will be given on the overall Site (typically Read or View Only)
* Permission for library members on Libraries - The Permission the Library Members group will be given on that particular library (Typically Contribute).
* Permission for library members on Folders - The Permission the Library Members group will be given on Folders within that particular library (Typically Contribute).
* Permission for library visitors on Site - The Permission Library visitors group will be given on the overall Site (typically Read or View Only)
* Permission for library visitors on Libraries - The Permission the Library Visitors group will be given on that particular library (Typically Read or View Only).
* Permission for library visitors on Folders- The Permission the Library Visitors group will be given on Folders within that particular library (Typically Read or View Only).
* Permission for Folder members on Site- The Permission Folder Members group will be given on the overall Site (typically Read or View Only)
* Permission for Folder members on Library -The Permission the Folder Members group will be given on the library containing the folder (Typically Read or View Only).
* Permission for Folder members on Folders - The Permission the Folder Members group will be given on the folder (Typically Contribute).
* Permission for Folder visitors on Site- The Permission Folder Visitors group will be given on the overall Site (typically Read or View Only)
* Permission for Folder visitors on Library - The Permission the Folder Visitors group will be given on the library containing the folder (Typically Read or View Only).
* Permission for Folder visitors on Folders- The Permission the Folder Visitors group will be given on the folder (Typically Read or View Only).
* Allow users to change generated security group names - When Libraries and Folders are created group names are generated based on the Library and Folder name. If this switch is turned on users can override that name. Otherwise the name can not be changed.
* Private Folders - If this switch is turned OFF, the Manage Folders command will not be shown. Secured subfolders cannot be created.
* App Insights instrumentation key- Optional App Insights instrumentation key to send telemetry to app insights if errors occur.
## Features
* Allows for creatiion of Libraries and folders with discrete configurable security groups.
* When libraries are deleted or archived using the app, all associated security groups are automatically deleted and users ins those groups no longer have access
* Can be used as an alternative to MS Teams for sharing data with external counterparties. All the data is in one site so its easier to manage. Additionl libraries and content can be created at the site level to be shared with all people who have access to the site.
* Security is easy to manage, just go to the webpart and find the Library or folder you want to gran access to and click on the appropriate group. You can see who has access and add / remove users in one spot.
* The Recent Actibity command can be used to see what activity has taken place recently within the givern library.
* Note that if this application is used, users must be warned that they should NEVER add or remove groups on the site.
* As of July 2021 this app has been running in a production environment for 9 months with no reported issues.
## Disclaimer
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
## Help
We do not support samples, but we this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues.
If you encounter any issues while using this sample, [create a new issue](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=bug-report.yml&sample=react-private-libraries&authors=@russgove&title=react-private-libraries%20-%20).
For questions regarding this sample, [create a new question](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=question.yml&sample=react-private-libraries&authors=@russgove&title=react-private-libraries%20-%20).
Finally, if you have an idea for improvement, [make a suggestion](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected&template=suggestion.yml&sample=react-private-libraries&authors=@russgove&title=react-private-libraries%20-%20).
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-private-libraries" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -0,0 +1,51 @@
[
{
"name": "pnp-sp-dev-spfx-web-parts-react-provate-libraries",
"source": "pnp",
"title": "Private Library/Folder Manager",
"shortDescription": "This sample provides a webpart that can be used to manage Document Libraries with Secured Subfolders.",
"url": "https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-provate-libraries",
"longDescription": [
"This sample provides a webpart that can be used to manage Document Libraries with Secured Subfolders. The use case this was developed for is a Request for Proposal site. A Document library is created for each RFP and subfolders are created within that Library for each external supplier invited to participate in that RFP.",
"The application manages all the security groups set up for the various libraries and folders so that suppliers only see RFP's they were invited to participate in and only thier folder in those libraries. General documents for the RFP that should be seen by everyone participating in the RFP can be put in the root folder of the library. General terms and conditions that everyone should see can be put at the root folder of the site."
],
"creationDateTime": "2021-07-02",
"updateDateTime": "2021-07-02",
"products": [
"SharePoint",
"Office"
],
"metadata": [
{
"key": "CLIENT-SIDE-DEV",
"value": "React"
},
{
"key": "SPFX-VERSION",
"value": "1.10.0"
}
],
"thumbnails": [
{
"type": "image",
"order": 100,
"url": "https://github.com/pnp/sp-dev-fx-webparts/raw/main/samples/react-provate-libraries/assets/HomeScreen.png",
"alt": "Preview"
}
],
"authors": [
{
"gitHubAccount": "russgove",
"pictureUrl": "https://github.com/russgove.png",
"name": "Russell Gove"
}
],
"references": [
{
"name": "Build your first SharePoint client-side web part",
"description": "Client-side web parts are client-side components that run in the context of a SharePoint page. Client-side web parts can be deployed to SharePoint environments that support the SharePoint Framework. You can also use modern JavaScript web frameworks, tools, and libraries to build them.",
"url": "https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/build-a-hello-world-web-part"
}
]
}
]

View File

@ -0,0 +1,29 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"vendor-maintenance-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/vendorMaintenance/VendorMaintenanceWebPart.js",
"manifest": "./src/webparts/vendorMaintenance/VendorMaintenanceWebPart.manifest.json"
}
]
},
"request-maintenance-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/requestMaintenance/RequestMaintenanceWebPart.js",
"manifest": "./src/webparts/requestMaintenance/RequestMaintenanceWebPart.manifest.json"
}
]
}
},
"externals": {},
"localizedResources": {
"VendorMaintenanceWebPartStrings": "lib/webparts/vendorMaintenance/loc/{locale}.js",
"ControlStrings": "node_modules/@pnp/spfx-controls-react/lib/loc/{locale}.js",
"PropertyControlStrings": "node_modules/@pnp/spfx-property-controls/lib/loc/{locale}.js",
"RequestMaintenanceWebPartStrings": "lib/webparts/requestMaintenance/loc/{locale}.js"
}
}

View File

@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json",
"deployCdnPath": "temp/deploy"
}

View File

@ -0,0 +1,7 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
"workingDir": "./temp/deploy/",
"account": "<!-- STORAGE ACCOUNT NAME -->",
"container": "r-fx-portal",
"accessKey": "<!-- ACCESS KEY -->"
}

View File

@ -0,0 +1,13 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "r-fx-portal-client-side-solution",
"id": "955d006f-7cc7-461f-8c5d-29593aebac61",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"isDomainIsolated": false
},
"paths": {
"zippedPackage": "solution/r-fx-portal.sppkg"
}
}

View File

@ -0,0 +1,12 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
"port": 4321,
"https": true,
"serveConfigurations": {
"default": {
"pageUrl": "https://russellwgove.sharepoint.com/sites/ReactPrivateLibraries/_layouts/15/workbench.aspx"
}
}
}

View File

@ -0,0 +1,4 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/write-manifests.schema.json",
"cdnBasePath": "<!-- PATH TO CDN -->"
}

View File

@ -0,0 +1,7 @@
'use strict';
const build = require('@microsoft/sp-build-web');
build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
build.initialize(require('gulp'));

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,54 @@
{
"name": "r-fx-portal",
"version": "0.0.1",
"private": true,
"main": "lib/index.js",
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"build": "gulp bundle",
"clean": "gulp clean",
"test": "gulp test"
},
"dependencies": {
"@microsoft/applicationinsights-react-js": "3.0.3",
"@microsoft/applicationinsights-web": "2.5.8",
"@microsoft/sp-core-library": "1.10.0",
"@microsoft/sp-lodash-subset": "1.10.0",
"@microsoft/sp-office-ui-fabric-core": "1.10.0",
"@microsoft/sp-property-pane": "1.10.0",
"@microsoft/sp-webpart-base": "1.10.0",
"@pnp/common": "2.0.6",
"@pnp/logging": "2.0.6",
"@pnp/odata": "2.0.6",
"@pnp/polyfill-ie11": "2.0.2",
"@pnp/sp": "2.0.6",
"@pnp/spfx-controls-react": "1.20.0",
"@pnp/spfx-property-controls": "1.20.0",
"@types/es6-promise": "0.0.33",
"@types/react": "16.8.8",
"@types/react-csv": "1.1.1",
"@types/react-dom": "16.8.3",
"@types/webpack-env": "1.13.1",
"date-fns": "2.16.1",
"office-ui-fabric-react": "6.189.2",
"react": "16.8.5",
"react-csv": "2.0.3",
"react-dom": "16.8.5"
},
"resolutions": {
"@types/react": "16.8.8"
},
"devDependencies": {
"@microsoft/sp-build-web": "1.10.0",
"@microsoft/sp-tslint-rules": "1.10.0",
"@microsoft/sp-module-interfaces": "1.10.0",
"@microsoft/sp-webpart-workbench": "1.10.0",
"@microsoft/rush-stack-compiler-3.3": "0.3.5",
"gulp": "~3.9.1",
"@types/chai": "3.4.34",
"@types/mocha": "2.2.38",
"ajv": "~5.2.2"
}
}

View File

@ -0,0 +1,14 @@
cd C:\Users\trwg1\sp-dev-fx-webparts\samples\react-private-libraries\scripts\
connect-pnponline -Url "https://{tenant}.sharepoint.com/sites/{site}"
$it=Get-Content '.\rfx.json'-Raw
$script=Add-PNPSiteScript -Title "RFx Lists" -Content $it
$design=Add-PNPSiteDesign `
-Title "Rfx Listes" `
-WebTemplate "64" `
-SiteScriptIds $script.Id `
-Description "Creates RFX Libraries"
Invoke-PnPSiteDesign -Identity $design.Id

View File

@ -0,0 +1,223 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/sp/site-design-script-actions.schema.json",
"actions": [{
"verb": "createSiteColumnXml",
"schemaXml": "<Field Type=\"Number\" DisplayName=\"Folder Visitors Group Id\" Group=\"_RFX\" EnforceUniqueValues=\"FALSE\" Required=\"FALSE\" Hidden=\"FALSE\" ReadOnly=\"FALSE\" CanToggleHidden=\"FALSE\" ID=\"{0c44d811-1669-4109-b2ae-133c764e2eb3}\" Name=\"rfxFolderVisitorsGroupId\" StaticName=\"rfxFolderVisitorsGroupId\" Percentage=\"FALSE\" />",
"pushChanges": true
},
{
"verb": "createSiteColumnXml",
"schemaXml": "<Field Type=\"Number\" DisplayName=\"Folder Members Group Id\" Group=\"_RFX\" EnforceUniqueValues=\"FALSE\" Required=\"FALSE\" Hidden=\"FALSE\" ReadOnly=\"FALSE\" CanToggleHidden=\"FALSE\" ID=\"{26b670d4-2d58-4798-becf-f869a3b28497}\" Name=\"rfxFolderMembersGroupId\" StaticName=\"rfxFolderMembersGroupId\" Percentage=\"FALSE\" Customization=\"\" PITarget=\"\" PrimaryPITarget=\"\" PIAttribute=\"\" PrimaryPIAttribute=\"\" Aggregation=\"\" Node=\"\" />",
"pushChanges": true
},
{
"verb": "createSiteColumnXml",
"schemaXml": "<Field Type=\"Text\" DisplayName=\"Closing Date\" Group=\"_RFX\" EnforceUniqueValues=\"FALSE\" Required=\"FALSE\" Hidden=\"FALSE\" ReadOnly=\"FALSE\" CanToggleHidden=\"FALSE\" ID=\"{2701f2bf-d45f-4672-9774-6dab88b9792d}\" Name=\"rfxClosingDate\" StaticName=\"rfxClosingDate\" MaxLength=\"255\" Customization=\"\" PITarget=\"\" PrimaryPITarget=\"\" PIAttribute=\"\" PrimaryPIAttribute=\"\" Aggregation=\"\" Node=\"\" />",
"pushChanges": true
},
{
"verb": "createSiteColumnXml",
"schemaXml": "<Field Type=\"User\" DisplayName=\"Contract Specialist\" Group=\"_RFX\" EnforceUniqueValues=\"FALSE\" Required=\"FALSE\" Hidden=\"FALSE\" ReadOnly=\"FALSE\" CanToggleHidden=\"FALSE\" ID=\"{843f09c7-19cb-4889-8b39-d3132643568c}\" Name=\"rfxContractSpecialist\" StaticName=\"rfxContractSpecialist\" ShowField=\"ImnName\" UserSelectionScope=\"0\" UserSelectionMode=\"PeopleOnly\" List=\"UserInfo\" Customization=\"\" PITarget=\"\" PrimaryPITarget=\"\" PIAttribute=\"\" PrimaryPIAttribute=\"\" Aggregation=\"\" Node=\"\" />",
"pushChanges": true
},
{
"verb": "createSiteColumnXml",
"schemaXml": "<Field Type=\"Note\" DisplayName=\"Description\" Group=\"Custom Columns\" EnforceUniqueValues=\"FALSE\" Required=\"FALSE\" Hidden=\"FALSE\" ReadOnly=\"FALSE\" CanToggleHidden=\"FALSE\" Sortable=\"FALSE\" ID=\"{a04fc484-b807-4fef-a970-cbd007deeb87}\" Name=\"rfxDescription\" StaticName=\"rfxDescription\" RichText=\"TRUE\" RichTextMode=\"FullHtml\" IsolateStyles=\"TRUE\" AppendOnly=\"FALSE\" NumLines=\"6\" UnlimitedLengthInDocumentLibrary=\"FALSE\" Customization=\"\" PITarget=\"\" PrimaryPITarget=\"\" PIAttribute=\"\" PrimaryPIAttribute=\"\" Aggregation=\"\" Node=\"\" />",
"pushChanges": true
},
{
"verb": "createSiteColumnXml",
"schemaXml": "<Field Type=\"Number\" DisplayName=\"Owners Group Id\" Group=\"_RFX\" EnforceUniqueValues=\"FALSE\" Required=\"FALSE\" Hidden=\"FALSE\" ReadOnly=\"FALSE\" CanToggleHidden=\"FALSE\" ID=\"{34889607-f472-4d16-8f5b-b5ba6617c6cd}\" Name=\"rfxOwnersGroupId\" StaticName=\"rfxOwnersGroupId\" Percentage=\"FALSE\" Customization=\"\" PITarget=\"\" PrimaryPITarget=\"\" PIAttribute=\"\" PrimaryPIAttribute=\"\" Aggregation=\"\" Node=\"\" />",
"pushChanges": true
},
{
"verb": "createSiteColumnXml",
"schemaXml": "<Field Type=\"Number\" DisplayName=\"Library Members Group Id\" Group=\"_RFX\" EnforceUniqueValues=\"FALSE\" Required=\"FALSE\" Hidden=\"FALSE\" ReadOnly=\"FALSE\" CanToggleHidden=\"FALSE\" ID=\"{a395c515-2e66-4009-9704-64533250b082}\" Name=\"rfxLibraryMembersGroupId\" StaticName=\"rfxLibraryMembersGroupId\" Percentage=\"FALSE\" Customization=\"\" PITarget=\"\" PrimaryPITarget=\"\" PIAttribute=\"\" PrimaryPIAttribute=\"\" Aggregation=\"\" Node=\"\" />",
"pushChanges": true
},
{
"verb": "createSiteColumnXml",
"schemaXml": "<Field Type=\"Number\" DisplayName=\"Library Visitors Group Id\" Group=\"Custom Columns\" EnforceUniqueValues=\"FALSE\" Required=\"FALSE\" Hidden=\"FALSE\" ReadOnly=\"FALSE\" CanToggleHidden=\"FALSE\" ID=\"{b0f7ea7e-1bf3-44d7-a293-9b1c6b6af67c}\" Name=\"rfxLibraryVisitorsGroupId\" StaticName=\"rfxLibraryVisitorsGroupId\" Percentage=\"FALSE\" Customization=\"\" PITarget=\"\" PrimaryPITarget=\"\" PIAttribute=\"\" PrimaryPIAttribute=\"\" Aggregation=\"\" Node=\"\" />",
"pushChanges": true
},
{
"verb": "createContentType",
"name": "RFXFolder",
"id": "0x010061598027686ADA4CA1D35CA1D0DEC987",
"description": "",
"parentId": "0x01",
"hidden": false,
"group": "_RFX",
"subactions": [{
"verb": "addSiteColumn",
"internalName": "RFx"
},
{
"verb": "addSiteColumn",
"internalName": "rfxFolderVisitorsGroupId"
},
{
"verb": "addSiteColumn",
"internalName": "rfxFolderMembersGroupId"
}
]
},
{
"verb": "createContentType",
"name": "RFX",
"id": "0x0100C654015369B79E4DA6572D4FE4C0BFBD",
"description": "",
"parentId": "0x01",
"hidden": false,
"group": "_RFX",
"subactions": [{
"verb": "addSiteColumn",
"internalName": "rfxClosingDate"
},
{
"verb": "addSiteColumn",
"internalName": "rfxContractSpecialist"
},
{
"verb": "addSiteColumn",
"internalName": "rfxDescription"
},
{
"verb": "addSiteColumn",
"internalName": "rfxOwnersGroupId"
},
{
"verb": "addSiteColumn",
"internalName": "rfxLibraryMembersGroupId"
},
{
"verb": "addSiteColumn",
"internalName": "rfxLibraryVisitorsGroupId"
}
]
},
{
"verb": "createSPList",
"listName": "RFxs",
"templateType": 100,
"subactions": [{
"verb": "addContentType",
"name": "RFX",
"id": "0x0100C654015369B79E4DA6572D4FE4C0BFBD"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field ID=\"{fa564e0f-0c70-4ab9-b863-0177e6ddd247}\" Type=\"Text\" Name=\"Title\" DisplayName=\"RFx Number\" Required=\"TRUE\" SourceID=\"http://schemas.microsoft.com/sharepoint/v3\" StaticName=\"Title\" FromBaseType=\"TRUE\" Indexed=\"TRUE\" EnforceUniqueValues=\"TRUE\" Hidden=\"FALSE\" ReadOnly=\"FALSE\" CanToggleHidden=\"FALSE\" MaxLength=\"255\" Sealed=\"FALSE\" Customization=\"\" PITarget=\"\" PrimaryPITarget=\"\" PIAttribute=\"\" PrimaryPIAttribute=\"\" Aggregation=\"\" Node=\"\" />"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field Type=\"Text\" DisplayName=\"Closing Date\" Group=\"_RFX\" EnforceUniqueValues=\"FALSE\" Required=\"FALSE\" Hidden=\"FALSE\" ReadOnly=\"FALSE\" CanToggleHidden=\"FALSE\" ID=\"{2701f2bf-d45f-4672-9774-6dab88b9792d}\" Name=\"rfxClosingDate\" StaticName=\"rfxClosingDate\" MaxLength=\"255\" />"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field Type=\"Number\" DisplayName=\"Library Members Group Id\" Group=\"_RFX\" EnforceUniqueValues=\"FALSE\" Required=\"FALSE\" Hidden=\"FALSE\" ReadOnly=\"FALSE\" CanToggleHidden=\"FALSE\" ID=\"{a395c515-2e66-4009-9704-64533250b082}\" Name=\"rfxLibraryMembersGroupId\" StaticName=\"rfxLibraryMembersGroupId\" Percentage=\"FALSE\" />"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field Type=\"Number\" DisplayName=\"Library Visitors Group Id\" Group=\"Custom Columns\" EnforceUniqueValues=\"FALSE\" Required=\"FALSE\" Hidden=\"FALSE\" ReadOnly=\"FALSE\" CanToggleHidden=\"FALSE\" ID=\"{b0f7ea7e-1bf3-44d7-a293-9b1c6b6af67c}\" Name=\"rfxLibraryVisitorsGroupId\" StaticName=\"rfxLibraryVisitorsGroupId\" Percentage=\"FALSE\" />"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field Type=\"Number\" DisplayName=\"Owners Group Id\" Group=\"_RFX\" EnforceUniqueValues=\"FALSE\" Required=\"FALSE\" Hidden=\"FALSE\" ReadOnly=\"FALSE\" CanToggleHidden=\"FALSE\" ID=\"{34889607-f472-4d16-8f5b-b5ba6617c6cd}\" Name=\"rfxOwnersGroupId\" StaticName=\"rfxOwnersGroupId\" Percentage=\"FALSE\" />"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field Type=\"Note\" DisplayName=\"Description\" Group=\"Custom Columns\" EnforceUniqueValues=\"FALSE\" Required=\"FALSE\" Hidden=\"FALSE\" ReadOnly=\"FALSE\" CanToggleHidden=\"FALSE\" Sortable=\"FALSE\" ID=\"{a04fc484-b807-4fef-a970-cbd007deeb87}\" Name=\"rfxDescription\" StaticName=\"rfxDescription\" RichText=\"TRUE\" RichTextMode=\"FullHtml\" IsolateStyles=\"TRUE\" AppendOnly=\"FALSE\" NumLines=\"6\" UnlimitedLengthInDocumentLibrary=\"FALSE\" />"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field Type=\"User\" DisplayName=\"Contract Specialist\" Group=\"_RFX\" EnforceUniqueValues=\"FALSE\" Required=\"FALSE\" Hidden=\"FALSE\" ReadOnly=\"FALSE\" CanToggleHidden=\"FALSE\" ID=\"{843f09c7-19cb-4889-8b39-d3132643568c}\" Name=\"rfxContractSpecialist\" StaticName=\"rfxContractSpecialist\" ShowField=\"ImnName\" UserSelectionScope=\"0\" UserSelectionMode=\"PeopleOnly\" List=\"UserInfo\" />"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field ID=\"{bc91a437-52e7-49e1-8c4e-4698904b2b6d}\" ReadOnly=\"TRUE\" Type=\"Computed\" Name=\"LinkTitleNoMenu\" DisplayName=\"RFx Number\" Dir=\"\" DisplayNameSrcField=\"Title\" AuthoringInfo=\"(linked to item)\" EnableLookup=\"TRUE\" ListItemMenuAllowed=\"Prohibited\" LinkToItemAllowed=\"Prohibited\" SourceID=\"http://schemas.microsoft.com/sharepoint/v3\" StaticName=\"LinkTitleNoMenu\" FromBaseType=\"TRUE\"><FieldRefs><FieldRef Name=\"Title\" /><FieldRef Name=\"LinkFilenameNoMenu\" /></FieldRefs><DisplayPattern><IfEqual><Expr1><LookupColumn Name=\"FSObjType\" /></Expr1><Expr2>1</Expr2><Then><Field Name=\"LinkFilenameNoMenu\" /></Then><Else><HTML><![CDATA[<a onfocus=\"OnLink(this)\" href=\"]]></HTML><URL /><HTML><![CDATA[\" onclick=\"EditLink2(this,]]></HTML><Counter Type=\"View\" /><HTML><![CDATA[);return false;\" target=\"_self\">]]></HTML><Column HTMLEncode=\"TRUE\" Name=\" Title\" Default=\"(no title)\" /><IfEqual><Expr1><GetVar Name=\"ShowAccessibleIcon\" /></Expr1><Expr2>1</Expr2><Then><HTML><![CDATA[<img src=\"/_layouts/15/images/blank.gif?rev=47\" class=\"ms-hidden\" border=\"0\" width=\"1\" height=\"1\" alt=\"Use SHIFT+ENTER to open the menu (new window).\"/>]]></HTML></Then></IfEqual><HTML><![CDATA[</a>]]></HTML><IfNew><HTML><![CDATA[<img src=\"/_layouts/1033/images/new.gif\" alt=\"]]></HTML><HTML>New</HTML><HTML><![CDATA[\" class=\"ms-newgif\" />]]></HTML></IfNew></Else></IfEqual></DisplayPattern></Field>"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field ID=\"{82642ec8-ef9b-478f-acf9-31f7d45fbc31}\" ReadOnly=\"TRUE\" Type=\"Computed\" Name=\"LinkTitle\" DisplayName=\"RFx Number\" DisplayNameSrcField=\"Title\" ClassInfo=\"Menu\" AuthoringInfo=\"(linked to item with edit menu)\" ListItemMenuAllowed=\"Required\" LinkToItemAllowed=\"Prohibited\" SourceID=\"http://schemas.microsoft.com/sharepoint/v3\" StaticName=\"LinkTitle\" FromBaseType=\"TRUE\"><FieldRefs><FieldRef Name=\"Title\" /><FieldRef Name=\"LinkTitleNoMenu\" /><FieldRef Name=\"_EditMenuTableStart2\" /><FieldRef Name=\"_EditMenuTableEnd\" /></FieldRefs><DisplayPattern><FieldSwitch><Expr><GetVar Name=\"FreeForm\" /></Expr><Case Value=\"TRUE\"><Field Name=\"LinkTitleNoMenu\" /></Case><Default><HTML><![CDATA[<div class=\"ms-vb itx\" onmouseover=\"OnItem(this)\" CTXName=\"ctx]]></HTML><Field Name=\"_EditMenuTableStart2\" /><HTML><![CDATA[\">]]></HTML><Field Name=\"LinkTitleNoMenu\" /><HTML><![CDATA[</div>]]></HTML><HTML><![CDATA[<div class=\"s4-ctx\" onmouseover=\"OnChildItem(this.parentNode); return false;\">]]></HTML><HTML><![CDATA[<span>&nbsp;</span>]]></HTML><HTML><![CDATA[<a onfocus=\"OnChildItem(this.parentNode.parentNode); return false;\" onclick=\"PopMenuFromChevron(event); return false;\" href=\"javascript:;\" title=\"Open Menu\"></a>]]></HTML><HTML><![CDATA[<span>&nbsp;</span>]]></HTML><HTML><![CDATA[</div>]]></HTML></Default></FieldSwitch></DisplayPattern></Field>"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field ID=\"{5f190d91-3dbc-4489-9878-3c092caf35b6}\" Hidden=\"TRUE\" ReadOnly=\"TRUE\" Type=\"Computed\" Name=\"LinkTitle2\" DisplayName=\"RFx Number\" DisplayNameSrcField=\"Title\" ClassInfo=\"Menu\" AuthoringInfo=\"(linked to item with edit menu) (old)\" SourceID=\"http://schemas.microsoft.com/sharepoint/v3\" StaticName=\"LinkTitle2\" FromBaseType=\"TRUE\"><FieldRefs><FieldRef Name=\"Title\" /><FieldRef Name=\"LinkTitleNoMenu\" /><FieldRef Name=\"_EditMenuTableStart\" /><FieldRef Name=\"_EditMenuTableEnd\" /></FieldRefs><DisplayPattern><FieldSwitch><Expr><GetVar Name=\"FreeForm\" /></Expr><Case Value=\"TRUE\"><Field Name=\"LinkTitleNoMenu\" /></Case><Default><Field Name=\"_EditMenuTableStart\" /><SetVar Name=\"ShowAccessibleIcon\" Value=\"1\" /><Field Name=\"LinkTitleNoMenu\" /><SetVar Name=\"ShowAccessibleIcon\" Value=\"0\" /><Field Name=\"_EditMenuTableEnd\" /></Default></FieldSwitch></DisplayPattern></Field>"
},
{
"verb": "addSPView",
"name": "All Items",
"viewFields": [
"LinkTitle",
"rfxClosingDate",
"rfxContractSpecialist",
"rfxOwnersGroupId",
"rfxLibraryMembersGroupId",
"rfxLibraryVisitorsGroupId"
],
"query": "",
"rowLimit": 30,
"isPaged": true,
"makeDefault": true,
"replaceViewFields": true
}
]
},
{
"verb": "createSPList",
"listName": "RFXFolders",
"templateType": 100,
"subactions": [{
"verb": "addContentType",
"name": "RFXFolder",
"id": "0x010061598027686ADA4CA1D35CA1D0DEC987"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field ID=\"{fa564e0f-0c70-4ab9-b863-0177e6ddd247}\" Type=\"Text\" Name=\"Title\" DisplayName=\"Folder Name\" Required=\"TRUE\" SourceID=\"http://schemas.microsoft.com/sharepoint/v3\" StaticName=\"Title\" FromBaseType=\"TRUE\" EnforceUniqueValues=\"FALSE\" Hidden=\"FALSE\" ReadOnly=\"FALSE\" CanToggleHidden=\"FALSE\" MaxLength=\"255\" Sealed=\"FALSE\" Customization=\"\" PITarget=\"\" PrimaryPITarget=\"\" PIAttribute=\"\" PrimaryPIAttribute=\"\" Aggregation=\"\" Node=\"\" />"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field Type=\"Number\" DisplayName=\"Folder Visitors Group Id\" Group=\"_RFX\" EnforceUniqueValues=\"FALSE\" Required=\"FALSE\" Hidden=\"FALSE\" ReadOnly=\"FALSE\" CanToggleHidden=\"FALSE\" ID=\"{0c44d811-1669-4109-b2ae-133c764e2eb3}\" Name=\"rfxFolderVisitorsGroupId\" StaticName=\"rfxFolderVisitorsGroupId\" Percentage=\"FALSE\" />"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field Type=\"Number\" DisplayName=\"Folder Members Group Id\" Group=\"_RFX\" EnforceUniqueValues=\"FALSE\" Required=\"FALSE\" Hidden=\"FALSE\" ReadOnly=\"FALSE\" CanToggleHidden=\"FALSE\" ID=\"{26b670d4-2d58-4798-becf-f869a3b28497}\" Name=\"rfxFolderMembersGroupId\" StaticName=\"rfxFolderMembersGroupId\" Percentage=\"FALSE\" />"
},
{
"verb": "addSPLookupFieldXml",
"schemaXml": "<Field Type=\"Lookup\" DisplayName=\"RFx\" Group=\"_RFX\" EnforceUniqueValues=\"FALSE\" Required=\"FALSE\" Hidden=\"FALSE\" ReadOnly=\"FALSE\" CanToggleHidden=\"FALSE\" ID=\"{dc4715d2-d74f-41bc-80cb-ed55ef102a7a}\" Name=\"RFx\" StaticName=\"RFx\" ShowField=\"Title\" UnlimitedLengthInDocumentLibrary=\"FALSE\" />",
"targetListName": "RFxs"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field ID=\"{bc91a437-52e7-49e1-8c4e-4698904b2b6d}\" ReadOnly=\"TRUE\" Type=\"Computed\" Name=\"LinkTitleNoMenu\" DisplayName=\"Folder Name\" Dir=\"\" DisplayNameSrcField=\"Title\" AuthoringInfo=\"(linked to item)\" EnableLookup=\"TRUE\" ListItemMenuAllowed=\"Prohibited\" LinkToItemAllowed=\"Prohibited\" SourceID=\"http://schemas.microsoft.com/sharepoint/v3\" StaticName=\"LinkTitleNoMenu\" FromBaseType=\"TRUE\"><FieldRefs><FieldRef Name=\"Title\" /><FieldRef Name=\"LinkFilenameNoMenu\" /></FieldRefs><DisplayPattern><IfEqual><Expr1><LookupColumn Name=\"FSObjType\" /></Expr1><Expr2>1</Expr2><Then><Field Name=\"LinkFilenameNoMenu\" /></Then><Else><HTML><![CDATA[<a onfocus=\"OnLink(this)\" href=\"]]></HTML><URL /><HTML><![CDATA[\" onclick=\"EditLink2(this,]]></HTML><Counter Type=\"View\" /><HTML><![CDATA[);return false;\" target=\"_self\">]]></HTML><Column HTMLEncode=\"TRUE\" Name=\"Title\" Default=\"(no title)\" /><IfEqual><Expr1><GetVar Name=\"ShowAccessibleIcon\" /></Expr1><Expr2>1</Expr2><Then><HTML><![CDATA[<img src=\"/_layouts/15/images/blank.gif?rev=47\" class=\"ms-hidden\" border=\"0\" width=\"1\" height=\"1\" alt=\"Use SHIFT+ENTER to open the menu (new window).\"/>]]></HTML></Then></IfEqual><HTML><![CDATA[</a>]]></HTML><IfNew><HTML><![CDATA[<img src=\"/_layouts/1033/images/new.gif\" alt=\"]]></HTML><HTML>New</HTML><HTML><![CDATA[\" class=\"ms-newgif\" />]]></HTML></IfNew></Else></IfEqual></DisplayPattern></Field>"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field ID=\"{82642ec8-ef9b-478f-acf9-31f7d45fbc31}\" ReadOnly=\"TRUE\" Type=\"Computed\" Name=\"LinkTitle\" DisplayName=\"Folder Name\" DisplayNameSrcField=\"Title\" ClassInfo=\"Menu\" AuthoringInfo=\"(linked to item with edit menu)\" ListItemMenuAllowed=\"Required\" LinkToItemAllowed=\"Prohibited\" SourceID=\"http://schemas.microsoft.com/sharepoint/v3\" StaticName=\"LinkTitle\" FromBaseType=\"TRUE\"><FieldRefs><FieldRef Name=\"Title\" /><FieldRef Name=\"LinkTitleNoMenu\" /><FieldRef Name=\"_EditMenuTableStart2\" /><FieldRef Name=\"_EditMenuTableEnd\" /></FieldRefs><DisplayPattern><FieldSwitch><Expr><GetVar Name=\"FreeForm\" /></Expr><Case Value=\"TRUE\"><Field Name=\"LinkTitleNoMenu\" /></Case><Default><HTML><![CDATA[<div class=\"ms-vb itx\" onmouseover=\"OnItem(this)\" CTXName=\"ctx]]></HTML><Field Name=\"_EditMenuTableStart2\" /><HTML><![CDATA[\">]]></HTML><Field Name=\"LinkTitleNoMenu\" /><HTML><![CDATA[</div>]]></HTML><HTML><![CDATA[<div class=\"s4-ctx\" onmouseover=\"OnChildItem(this.parentNode); return false;\">]]></HTML><HTML><![CDATA[<span>&nbsp;</span>]]></HTML><HTML><![CDATA[<a onfocus=\"OnChildItem(this.parentNode.parentNode); return false;\" onclick=\"PopMenuFromChevron(event); return false;\" href=\"javascript:;\" title=\"Open Menu\"></a>]]></HTML><HTML><![CDATA[<span>&nbsp;</span>]]></HTML><HTML><![CDATA[</div>]]></HTML></Default></FieldSwitch></DisplayPattern></Field>"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field ID=\"{5f190d91-3dbc-4489-9878-3c092caf35b6}\" Hidden=\"TRUE\" ReadOnly=\"TRUE\" Type=\"Computed\" Name=\"LinkTitle2\" DisplayName=\"Folder Name\" DisplayNameSrcField=\"Title\" ClassInfo=\"Menu\" AuthoringInfo=\"(linked to item with edit menu) (old)\" SourceID=\"http://schemas.microsoft.com/sharepoint/v3\" StaticName=\"LinkTitle2\" FromBaseType=\"TRUE\"><FieldRefs><FieldRef Name=\"Title\" /><FieldRef Name=\"LinkTitleNoMenu\" /><FieldRef Name=\"_EditMenuTableStart\" /><FieldRef Name=\"_EditMenuTableEnd\" /></FieldRefs><DisplayPattern><FieldSwitch><Expr><GetVar Name=\"FreeForm\" /></Expr><Case Value=\"TRUE\"><Field Name=\"LinkTitleNoMenu\" /></Case><Default><Field Name=\"_EditMenuTableStart\" /><SetVar Name=\"ShowAccessibleIcon\" Value=\"1\" /><Field Name=\"LinkTitleNoMenu\" /><SetVar Name=\"ShowAccessibleIcon\" Value=\"0\" /><Field Name=\"_EditMenuTableEnd\" /></Default></FieldSwitch></DisplayPattern></Field>"
},
{
"verb": "addSPView",
"name": "All Items",
"viewFields": [
"LinkTitle",
"RFx",
"rfxFolderVisitorsGroupId",
"rfxFolderMembersGroupId"
],
"query": "",
"rowLimit": 30,
"isPaged": true,
"makeDefault": true,
"replaceViewFields": true
}
]
}
]
}

View File

@ -0,0 +1,209 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/sp/site-design-script-actions.schema.json",
"actions": [{
"verb": "createSiteColumnXml",
"schemaXml": null,
"pushChanges": true
},
{
"verb": "createSiteColumnXml",
"schemaXml": "<Field Type='Number' DisplayName='Folder Visitors Group Id' Group='_RFX' EnforceUniqueValues='FALSE' Required='FALSE' Hidden='FALSE' ReadOnly='FALSE' CanToggleHidden = 'FALSE' ID='{0c44d811-1669-4109-b2ae-133c764e2eb3}' Name='rfxFolderVisitorsGroupId' StaticName='rfxFolderVisitorsGroupId' Percentage='FALSE' Customization='' PITarget='' PrimaryPITarget='' PIAttribute='' PrimaryPIAttribute='' Aggregation='' Node='' />",
"pushChanges": true
},
{
"verb": "createSiteColumnXml",
"schemaXml": "<Field Type='Number' DisplayName='Folder Members Group Id' Group='_RFX' EnforceUniqueValues='FALSE' Required='FALSE' Hidden='FALSE' ReadOnly='FALSE' CanToggleHidden = 'FALSE' ID='{26b670d4-2d58-4798-becf-f869a3b28497}' Name='rfxFolderMembersGroupId' StaticName='rfxFolderMembersGroupId' Percentage='FALSE' Customization='' PITarget = '' PrimaryPITarget='' PIAttribute='' PrimaryPIAttribute='' Aggregation='' Node='' />",
"pushChanges": true
},
{
"verb": "createSiteColumnXml",
"schemaXml": "<Field Type='Text' DisplayName='Closing Date' Group='_RFX' EnforceUniqueValues='FALSE' Required='FALSE' Hidden='FALSE' ReadOnly='FALSE' CanToggleHidden = 'FALSE' ID='{2701f2bf-d45f-4672-9774-6dab88b9792d}' Name='rfxClosingDate' StaticName='rfxClosingDate' MaxLength='255' Customization='' PITarget='' PrimaryPITarget='' PIAttribute = '' PrimaryPIAttribute='' Aggregation='' Node='' />",
"pushChanges": true
},
{
"verb": "createSiteColumnXml",
"schemaXml": "<Field Type='User' DisplayName='Contract Specialist' Group='_RFX' EnforceUniqueValues='FALSE' Required='FALSE' Hidden='FALSE' ReadOnly='FALSE' CanToggleHidden = 'FALSE' ID='{843f09c7-19cb-4889-8b39-d3132643568c}' Name='rfxContractSpecialist' StaticName='rfxContractSpecialist' ShowField='ImnName' UserSelectionScope='0' UserSelectionMode = 'PeopleOnly' List='UserInfo' Customization='' PITarget='' PrimaryPITarget='' PIAttribute='' PrimaryPIAttribute='' Aggregation='' Node='' />",
"pushChanges": true
},
{
"verb": "createSiteColumnXml",
"schemaXml": "<Field Type='Note' DisplayName='Description' Group='Custom Columns' EnforceUniqueValues='FALSE' Required='FALSE' Hidden='FALSE' ReadOnly='FALSE' CanToggleHidden = 'FALSE' Sortable='FALSE' ID='{a04fc484-b807-4fef-a970-cbd007deeb87}' Name='rfxDescription' StaticName='rfxDescription' RichText='TRUE' RichTextMode='FullHtml' IsolateStyles = 'TRUE' AppendOnly='FALSE' NumLines='6' UnlimitedLengthInDocumentLibrary='FALSE' Customization='' PITarget='' PrimaryPITarget='' PIAttribute='' PrimaryPIAttribute = '' Aggregation='' Node='' />",
"pushChanges": true
},
{
"verb": "createSiteColumnXml",
"schemaXml": "<Field Type='Number' DisplayName='Owners Group Id' Group='_RFX' EnforceUniqueValues='FALSE' Required='FALSE' Hidden='FALSE' ReadOnly='FALSE' CanToggleHidden = 'FALSE' ID='{34889607-f472-4d16-8f5b-b5ba6617c6cd}' Name='rfxOwnersGroupId' StaticName='rfxOwnersGroupId' Percentage='FALSE' Customization='' PITarget='' PrimaryPITarget = '' PIAttribute='' PrimaryPIAttribute='' Aggregation='' Node='' />",
"pushChanges": true
},
{
"verb": "createSiteColumnXml",
"schemaXml": "<Field Type='Number' DisplayName='Library Members Group Id' Group='_RFX' EnforceUniqueValues='FALSE' Required='FALSE' Hidden='FALSE' ReadOnly='FALSE' CanToggleHidden = 'FALSE' ID='{a395c515-2e66-4009-9704-64533250b082}' Name='rfxLibraryMembersGroupId' StaticName='rfxLibraryMembersGroupId' Percentage='FALSE' Customization='' PITarget='' PrimaryPITarget='' PIAttribute='' PrimaryPIAttribute='' Aggregation='' Node='' />",
"pushChanges": true
},
{
"verb": "createSiteColumnXml",
"schemaXml": "<Field Type='Number' DisplayName='Library Visitors Group Id' Group='Custom Columns' EnforceUniqueValues='FALSE' Required='FALSE' Hidden='FALSE' ReadOnly = 'FALSE' CanToggleHidden='FALSE' ID='{b0f7ea7e-1bf3-44d7-a293-9b1c6b6af67c}' Name='rfxLibraryVisitorsGroupId' StaticName='rfxLibraryVisitorsGroupId' Percentage='FALSE' Customization = '' PITarget='' PrimaryPITarget='' PIAttribute='' PrimaryPIAttribute='' Aggregation='' Node='' />",
"pushChanges": true
},
{
"verb": "createContentType",
"name": "RFXFolder",
"id": "0x010061598027686ADA4CA1D35CA1D0DEC987",
"description": "",
"parentId": "0x01",
"hidden": false,
"group": "_RFX",
"subactions": [{
"verb": "addSiteColumn",
"internalName": "RFx"
},
{
"verb": "addSiteColumn",
"internalName": "rfxFolderVisitorsGroupId"
},
{
"verb": "addSiteColumn",
"internalName": "rfxFolderMembersGroupId"
}
]
},
{
"verb": "createContentType",
"name": "RFX",
"id": "0x0100C654015369B79E4DA6572D4FE4C0BFBD",
"description": "",
"parentId": "0x01",
"hidden": false,
"group": "_RFX",
"subactions": [{
"verb": "addSiteColumn",
"internalName": "rfxClosingDate"
},
{
"verb": "addSiteColumn",
"internalName": "rfxContractSpecialist"
},
{
"verb": "addSiteColumn",
"internalName": "rfxDescription"
},
{
"verb": "addSiteColumn",
"internalName": "rfxOwnersGroupId"
},
{
"verb": "addSiteColumn",
"internalName": "rfxLibraryMembersGroupId"
},
{
"verb": "addSiteColumn",
"internalName": "rfxLibraryVisitorsGroupId"
}
]
},
{
"verb": "createSPList",
"listName": "RFxs",
"templateType": 100,
"subactions": [{
"verb": "addContentType",
"name": "RFX",
"id": "0x0100C654015369B79E4DA6572D4FE4C0BFBD"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field ID='{fa564e0f-0c70-4ab9-b863-0177e6ddd247}' Type='Text' Name='Title' DisplayName='RFx Number' Required='TRUE' SourceID='http://schemas.microsoft.com/sharepoint/v3' StaticName='Title' FromBaseType='TRUE' Indexed='TRUE' EnforceUniqueValues='TRUE' Hidden='FALSE' ReadOnly='FALSE' CanToggleHidden='FALSE' MaxLength = '255' Sealed='FALSE' Customization='' PITarget='' PrimaryPITarget='' PIAttribute='' PrimaryPIAttribute='' Aggregation='' Node='' />"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field Type='Text' DisplayName='Closing Date' Group='_RFX' EnforceUniqueValues='FALSE' Required='FALSE' Hidden='FALSE' ReadOnly='FALSE' CanToggleHidden = 'FALSE' ID='{2701f2bf-d45f-4672-9774-6dab88b9792d}' Name='rfxClosingDate' StaticName='rfxClosingDate' MaxLength='255' />"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field Type='Number' DisplayName='Library Members Group Id' Group='_RFX' EnforceUniqueValues='FALSE' Required='FALSE' Hidden='FALSE' ReadOnly='FALSE' CanToggleHidden='FALSE' ID='{a395c515-2e66-4009-9704-64533250b082}' Name='rfxLibraryMembersGroupId' StaticName='rfxLibraryMembersGroupId' Percentage='FALSE' />"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field Type='Number' DisplayName='Library Visitors Group Id' Group='Custom Columns' EnforceUniqueValues='FALSE' Required='FALSE' Hidden='FALSE' ReadOnly = 'FALSE' CanToggleHidden='FALSE' ID='{b0f7ea7e-1bf3-44d7-a293-9b1c6b6af67c}' Name='rfxLibraryVisitorsGroupId' StaticName='rfxLibraryVisitorsGroupId' Percentage='FALSE' /> "
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field Type='Number' DisplayName='Owners Group Id' Group='_RFX' EnforceUniqueValues='FALSE' Required='FALSE' Hidden='FALSE' ReadOnly='FALSE' CanToggleHidden = 'FALSE' ID='{34889607-f472-4d16-8f5b-b5ba6617c6cd}' Name='rfxOwnersGroupId' StaticName='rfxOwnersGroupId' Percentage='FALSE' />"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field Type='Note' DisplayName='Description' Group='Custom Columns' EnforceUniqueValues='FALSE' Required='FALSE' Hidden='FALSE' ReadOnly='FALSE' CanToggleHidden = 'FALSE' Sortable='FALSE' ID='{a04fc484-b807-4fef-a970-cbd007deeb87}' Name='rfxDescription' StaticName='rfxDescription' RichText='TRUE' RichTextMode='FullHtml' IsolateStyles='TRUE' AppendOnly='FALSE' NumLines='6' UnlimitedLengthInDocumentLibrary='FALSE' />"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field Type='User' DisplayName='Contract Specialist' Group='_RFX' EnforceUniqueValues='FALSE' Required='FALSE' Hidden='FALSE' ReadOnly='FALSE' CanToggleHidden = 'FALSE' ID = '{843f09c7-19cb-4889-8b39-d3132643568c}' Name = 'rfxContractSpecialist' StaticName = 'rfxContractSpecialist' ShowField = 'ImnName' UserSelectionScope = '0' UserSelectionMode = 'PeopleOnly' List = 'UserInfo' / > "
},
{
"verb": "addSPView",
"name": "All Items",
"viewFields": [
"LinkTitle",
"rfxClosingDate",
"rfxContractSpecialist",
"rfxOwnersGroupId",
"rfxLibraryMembersGroupId",
"rfxLibraryVisitorsGroupId"
],
"query": "",
"rowLimit": 30,
"isPaged": true,
"makeDefault": true,
"replaceViewFields": true
}
]
}, {
"verb": "createSPList",
"listName": "RFXFolders",
"templateType": 100,
"subactions": [{
"verb": "addContentType",
"name": "RFXFolder",
"id": "0x010061598027686ADA4CA1D35CA1D0DEC987"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field ID='{fa564e0f-0c70-4ab9-b863-0177e6ddd247}' Type='Text' Name='Title' DisplayName='Folder Name' Required='TRUE' SourceID='http://schemas.microsoft.com /sharepoint/v3' StaticName='Title' FromBaseType='TRUE' EnforceUniqueValues='FALSE' Hidden='FALSE' ReadOnly='FALSE' CanToggleHidden='FALSE' MaxLength='255' Sealed = 'FALSE' Customization = '' PITarget = '' PrimaryPITarget = '' PIAttribute = '' PrimaryPIAttribute = '' Aggregation = '' Node = '' />"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field Type='Number' DisplayName='Folder Visitors Group Id' Group='_RFX' EnforceUniqueValues='FALSE' Required='FALSE' Hidden='FALSE' ReadOnly='FALSE' CanToggleHidden='FALSE' ID='{0c44d811-1669-4109-b2ae-133c764e2eb3}' Name='rfxFolderVisitorsGroupId' StaticName='rfxFolderVisitorsGroupId' Percentage='FALSE' />"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field Type='Number' DisplayName='Folder Members Group Id' Group='_RFX' EnforceUniqueValues='FALSE' Required='FALSE' Hidden='FALSE' ReadOnly='FALSE' CanToggleHidden='FALSE' ID='{26b670d4-2d58-4798-becf-f869a3b28497}' Name='rfxFolderMembersGroupId' StaticName='rfxFolderMembersGroupId' Percentage='FALSE' />"
},
{
"verb": "addSPLookupFieldXml",
"schemaXml": "<Field Type='Lookup' DisplayName='RFx' Group='_RFX' EnforceUniqueValues='FALSE' Required='FALSE' Hidden='FALSE' ReadOnly='FALSE' CanToggleHidden='FALSE' ID=' { dc4715d2 - d74f - 41 bc - 80 cb - ed55ef102a7a } ' Name=' RFx ' StaticName=' RFx ' ShowField=' Title ' UnlimitedLengthInDocumentLibrary=' FALSE ' />",
"targetListName": "RFxs"
},
{
"verb": "addSPFieldXml",
"schemaXml": "<Field ID='{5f190d91-3dbc-4489-9878-3c092caf35b6}' Hidden='TRUE' ReadOnly='TRUE' Type='Computed' Name='LinkTitle2' DisplayName='Folder Name' DisplayNameSrcField = 'Title' ClassInfo = 'Menu' AuthoringInfo = '(linked to item with edit menu) (old)' SourceID='http://schemas.microsoft.com/sharepoint/v3' StaticName = 'LinkTitle2' FromBaseType = 'TRUE' > < FieldRefs > < FieldRef Name = 'Title' / > < FieldRef Name = 'LinkTitleNoMenu' / > < FieldRef Name = '_EditMenuTableStart' / > < FieldRef Name = '_EditMenuTableEnd' / > < /FieldRefs > < DisplayPattern > < FieldSwitch > < Expr > < GetVar Name = 'FreeForm' / > < /Expr><Case Value='TRUE'><Field Name='LinkTitleNoMenu' / > < /Case><Default><Field Name='_EditMenuTableStart' / > <SetVar Name = 'ShowAccessibleIcon' Value = '1' / > < Field Name = 'LinkTitleNoMenu' / > < SetVar Name = 'ShowAccessibleIcon' Value = '0' / > < Field Name = '_EditMenuTableEnd' / > < /Default></FieldSwitch > < /DisplayPattern></Field > "
}, {
"verb": "addSPView",
"name": "All Items",
"viewFields": [
"LinkTitle",
"RFx",
"rfxFolderVisitorsGroupId",
"rfxFolderMembersGroupId"
],
"query": "",
"rowLimit": 30,
"isPaged": true,
"makeDefault": true,
"replaceViewFields": true
}
]
}
]
}

View File

@ -0,0 +1 @@
// A file is required to be in the root of the /src directory by the TypeScript compiler

View File

@ -0,0 +1,11 @@
export interface IActivity {
userEmail: string;
userDisplayName: string;
driveItemType: string;
driveItemName: string;
driveItemParentReference: string;
activityRecordedTime:Date;
action:string;
}

View File

@ -0,0 +1,8 @@
export interface IDrive {
description: string;
id: string;
name: string;
webUrl: string;
driveType: string;
}

View File

@ -0,0 +1,17 @@
export interface IRFx {
title: string;
closingDate:Date;
contractSpecialist:{
EMail:string
};
contractSpecialistId:number;
id:number; //the id of the listitem that holds the doclib title and securitygroup name
// internalSecurityGroupId:number;members
libraryMembersGroupId:number;
//externalSecurityGroupId:number;;visitors
libraryVisitorsGroupId:number;
libraryOwnersGroupId:number;
description:string;
}

View File

@ -0,0 +1,10 @@
export interface IRFxFolder {
title: string;
id:number; //the id of the listitem that holds the doclib title and securitygroup name
folderMembersGroupId:number;
folderVisitorsGroupId:number;
rfxId:number;
}

View File

@ -0,0 +1,7 @@
export interface IVendor {
title: string;
membersGroup:string;
id:number; //the id of the listitem that holds the doclib title and securitygroup name
}

View File

@ -0,0 +1,59 @@
import { SeverityLevel } from '@microsoft/applicationinsights-web';
import { ApplicationInsights } from '@microsoft/applicationinsights-web';
import { ReactPlugin } from '@microsoft/applicationinsights-react-js';
import {
ILogEntry,
ILogListener,
LogLevel
} from "@pnp/logging";
class CustomListener implements ILogListener {
private appInsights: ApplicationInsights;
private instrumentationKey: string;
constructor(instrumentationKey: string) {
this.instrumentationKey = instrumentationKey;
this.appInsights = this.getApplicationInsights();
}
public log(entry: ILogEntry): void {
if (entry.level == LogLevel.Error)
this.appInsights.trackException({
error: new Error(entry.message),
severityLevel: SeverityLevel.Error
});
else if (entry.level == LogLevel.Warning)
this.appInsights.trackException({
error: new Error(entry.message),
severityLevel: SeverityLevel.Warning
});
else if (entry.level == LogLevel.Info)
this.appInsights.trackException({
error: new Error(entry.message),
severityLevel: SeverityLevel.Information
});
else
this.appInsights.trackException({
error: new Error(entry.message),
severityLevel: SeverityLevel.Verbose
});
this.appInsights.trackTrace({ message: entry.message });
}
private getApplicationInsights(): ApplicationInsights {
debugger;
const reactPlugin = new ReactPlugin();
const applicationInsights = new ApplicationInsights({
config: {
instrumentationKey: this.instrumentationKey,
extensions: [reactPlugin]
}
});
applicationInsights.loadAppInsights();
return applicationInsights;
}
}
export default CustomListener;

View File

@ -0,0 +1,218 @@
import { sp, SPHttpClient } from "@pnp/sp";
import { ISiteGroup, ISiteGroupInfo } from '@pnp/sp/site-groups';
import { autobind } from 'office-ui-fabric-react/lib/Utilities';
import { IViewInfo } from '@pnp/sp/views';
import { IRoleDefinition, IRoleDefinitionInfo } from '@pnp/sp/security';
import { escape, findIndex, find } from '@microsoft/sp-lodash-subset';
import { IItem } from "@pnp/sp/items";
import { IRFxFolder } from '../models/IRFxFolder';
export default class RFXUtilities {
public roleDefs: IRoleDefinitionInfo[];
/**
* Sets the parent of a group to another group using JSOM calls (this is not supported in rest)
* @param groupId -- the ID of the group whose parent will be changed
* @param ownerGroupId -- the id of the group that will become the parent
*/
public static async setGroupOwner(groupId: number, ownerGroupId: number): Promise<void> {
const client = new SPHttpClient();
await Promise.all([sp.web.select("Url").get(), sp.site.select("Id").get()])
.then(async (siteData) => {
const siteObj = siteData[0];
const siteId = siteData[1];
const endpoint = siteObj.Url + `/_vti_bin/client.svc/ProcessQuery`;
const body = `<Request AddExpandoFieldTypeSuffix="true" SchemaVersion="15.0.0.0" LibraryVersion="15.0.0.0" ApplicationName=".NET Library" xmlns="http://schemas.microsoft.com/sharepoint/clientquery/2009">
<Actions>
<SetProperty Id="1" ObjectPathId="2" Name="Owner">
<Parameter ObjectPathId="3" />
</SetProperty>
<Method Name="Update" Id="4" ObjectPathId="2" />
</Actions>
<ObjectPaths>
<Identity Id="2" Name="740c6a0b-85e2-48a0-a494-e0f1759d4aa7:site:${siteId.Id}:g:${groupId}" />
<Identity Id="3" Name="740c6a0b-85e2-48a0-a494-e0f1759d4aa7:site:${siteId.Id}:g:${ownerGroupId}" />
</ObjectPaths>
</Request>`;
await client.post(endpoint, {
headers: {
"content-type": "text/xml"
},
body: body
})
.then((response) => {
return response.json().then((r) => {
if (r[0].ErrorInfo) {
return Promise.reject(r[0].ErrorInfo.ErrorMessage);
} else {
return Promise.resolve();
}
});
});
});
}
/**
* Gets the ID of a roledefinition with the given name
*
* @public
* @param {string} roleDefinitionName The name of the roleDefinition whose ID we want to get
* @returns {Promise<number>} The ID if the roleDefinition. If not found this will be -1
* @memberof DocLibSecurity
*/
public static getRoledefId(roleDefinitionName: string, roleDefinitions: Array<IRoleDefinitionInfo>): number {
for (const def of roleDefinitions) {
if (def.Name === roleDefinitionName) {
return def.Id;
}
}
return -1;
}
/**
* Grants a group access to a library
*
* @public
* @param {string} libraryName The name of the library to grant access to
* @param {string} groupName The name of the group to gtrant access for
* @param {string} roleName The role to assign the group to on this library
* @returns {Promise<any>}
* @memberof DocLibSecurity
*/
public static async grantGroupAccessToLibrary(libraryName: string, groupId: number, roleName: string, roleDefinitions: Array<IRoleDefinitionInfo>): Promise<any> {
const roleDefId = await RFXUtilities.getRoledefId(roleName, roleDefinitions);
if (roleDefId === -1) {
return Promise.reject(`"Role ${roleName} not found`);
}
return sp.web.lists.getByTitle(libraryName).roleAssignments.add(groupId, roleDefId);
}
public static async removeAccessToLibrary(libraryName: string, principalId: number, roleName: string, roleDefinitions: Array<IRoleDefinitionInfo>): Promise<any> {
const roleDefId = await RFXUtilities.getRoledefId(roleName, roleDefinitions);
if (roleDefId === -1) {
return Promise.reject(`"Role ${roleName} not found`);
}
return sp.web.lists.getByTitle(libraryName).roleAssignments.remove(principalId, roleDefId);
}
/**
* Determinse if a SiteGroup with the given name exists
*
* @public
* @param {string} groupName The name of the SiteGroup we want to check
* @returns {Promise<boolean>} True if SiteGroup exists , otherwise false
* @memberof DocLibSecurity
*/
public static doesGroupExist(groupName: string): Promise<boolean> {
return sp.web.siteGroups.getByName(groupName).get()
.then((list) => {
return true;
})
.catch((e) => {
return false;
});
}
// /**
// * Grants a group access to the site
// *
// * @public
// * @param {string} groupName The group name to be granted access
// * @param {string} roleName The role to assign the group to on this site
// * @returns {Promise<any>}
// * @memberof DocLibSecurity
// */
// // public static async grantNewGroupAccessToSite(groupName: string, roleName: string, roleDefinitions: Array<IRoleDefinitionInfo>): Promise<any> {
// // const roleDefId = await this.getRoledefId(roleName, roleDefinitions);
// // const grp = await sp.web.siteGroups.getByName(groupName).get();
// // return sp.web.roleAssignments.add(grp.Id, roleDefId);
// // }
public static async grantGroupIdAccessToSite(groupId: number, roleName: string, roleDefinitions: Array<IRoleDefinitionInfo>): Promise<any> {
const roleDefId = await this.getRoledefId(roleName, roleDefinitions);
return sp.web.roleAssignments.add(groupId, roleDefId);
}
/**
* Navigates to the default view of the selected lbrary
*
* @public
* @param {string} title -- the Title of the doclib to open
* @memberof DocLibSecurity
*/
public static linkToLibrary(title: string): void {
sp.web.lists.getByTitle(title).defaultView.get()
.then((view: IViewInfo) => {
window.location.pathname = view.ServerRelativeUrl;
});
}
public static linkToFolder(folder: IRFxFolder, rfxListName: string): void {
let ifrx = sp.web.lists.getByTitle(rfxListName).items.getById(folder.rfxId).get()
.then((rfx) => {
sp.web.lists.getByTitle(rfx["Title"]).rootFolder.folders.getByName(folder.title).get()
.then((item) => {
debugger;
window.location.pathname = item.ServerRelativeUrl;
});
});
}
/**
* Naviates to the Group Maintenance page for the selected Group
*
* @public
* @param {string} groupName The name of the Group
* @memberof DocLibSecurity
*/
public static linkToGroup(groupName: string, webServerRelativeUrl: string): void {
sp.web.siteGroups.getByName(groupName).get()
.then((grp: ISiteGroupInfo) => {
let newUrl = `${window.location.origin}${webServerRelativeUrl}/_layouts/15/people.aspx?MembershipGroupId=${grp.Id}`;
window.location.href = newUrl;
});
}
/**
* Naviates to the Group Maintenance page for the selected Group
*
* @public
* @param {string} groupName The name of the Group
* @memberof DocLibSecurity
*/
public static linkToGroupById(groupId: number, webServerRelativeUrl: string): void {
let newUrl = `${window.location.origin}${webServerRelativeUrl}/_layouts/15/people.aspx?MembershipGroupId=${groupId}`;
window.location.href = newUrl;
}
/**
* Delets a group with the given name
*
* @public
* @param {string} groupName the name of the group to remove
* @returns {Promise<void>}
* @memberof DocLibSecurity
*/
public static deletegroup(groupName: string): Promise<void> {
return sp.web.siteGroups.getByName(groupName).get()
.then((grp: ISiteGroupInfo) => {
sp.web.siteGroups.removeById(grp.Id);
});
}
public static getSiteGroupName(siteGroupId: number, siteGroups: Array<ISiteGroupInfo>): string {
let sg: ISiteGroupInfo = find(siteGroups, (sgx) => {
return sgx.Id === siteGroupId;
});
if (sg) {
return sg.Title;
}
else { return (`*${siteGroupId}*`); }
}
}

View File

@ -0,0 +1,47 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "bad86476-e6ad-4162-92a5-4663ed8bb68d",
"alias": "RequestMaintenanceWebPart",
"componentType": "WebPart",
// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,
// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,
"supportedHosts": [
"SharePointWebPart"
],
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": {
"default": "Other"
},
"title": {
"default": "RequestMaintenance"
},
"description": {
"default": "RequestMaintenance description"
},
"officeFabricIconFontName": "Page",
"properties": {
"rfxListTitle": "RFXs",
"rfxFoldersListTitle": "RFXFolders",
"archiveLibraryTitle": "Archive",
"enablePrivateFolders": true,
"roleDefinitionForLibraryMembersGroupOnSite": "Read",
"roleDefinitionForLibraryMembersGroupOnLibrary": "Contribute",
"roleDefinitionForLibraryMembersGroupOnFolder": "Contribute",
"roleDefinitionForLibraryVisitorsGroupOnSite": "Read",
"roleDefinitionForLibraryVisitorsGroupOnLibrary": "Read",
"roleDefinitionForLibraryVisitorsGroupOnFolder": "Read",
"roleDefinitionForFolderMembersOnSite": "Read",
"roleDefinitionForFolderMembersOnLibrary": "Read",
"roleDefinitionForFolderMembersOnFolder": "Edit",
"roleDefinitionForFolderVisitorsOnSite": "Read",
"roleDefinitionForFolderVisitorsOnLibrary": "Read",
"roleDefinitionForFolderVisitorsOnFolder": "Read"
}
}]
}

View File

@ -0,0 +1,291 @@
import CustomListener from "../../utilities/CustomListener";
import { IRequestMaintenanceProps } from './components/IRequestMaintenanceProps';
import RequestMaintenance from './components/RequestMaintenance';
import { IPropertyPaneConfiguration, PropertyPaneDropdown, PropertyPaneTextField, PropertyPaneToggle } from '@microsoft/sp-property-pane';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import { setup as pnpSetup } from "@pnp/common";
import { ConsoleListener, Logger, LogLevel } from "@pnp/logging";
import { sp } from "@pnp/sp";
import { IRoleDefinitionInfo } from '@pnp/sp/security';
import { ISiteGroupInfo } from '@pnp/sp/site-groups';
import * as React from 'react';
import * as ReactDom from 'react-dom';
import * as strings from 'RequestMaintenanceWebPartStrings';
import "@pnp/sp/security";
import "@pnp/sp/site-groups/web";
import "@pnp/sp/site-groups/web";
import "@pnp/sp/site-users";
import "@pnp/sp/webs";
//mport { ISiteUser } from '@pnp/sp/site-users';
export interface IRequestMaintenanceWebPartProps {
rfxListTitle: string; // the name of the list that holds all the RFX Info
rfxFoldersListTitle: string;// the name of the list that holds all the RFX folder Info
instrumentationKey: string; // app insights key
archiveLibraryTitle: string;
enablePrivateFolders: boolean;
roleDefinitionForLibraryMembersGroupOnLibrary: string;// each new RFX library has an group created for internal users. What role should that group have on trghe library (Contribute)
roleDefinitionForLibraryMembersGroupOnSite: string; // each new RFX library has an group created for internal users. What role should that group have on trghe site (READ)
roleDefinitionForLibraryMembersGroupOnFolder: string; // each new RFX library has an group created for internal users. What role should that group have on trghe site (READ)
roleDefinitionForLibraryVisitorsGroupOnLibrary: string;// each new RFX library has an group created for external users. What role should that group have on trghe library (Contribute)
roleDefinitionForLibraryVisitorsGroupOnSite: string; // each new RFX library has an group created for external users. What role should that group have on trghe site (READ)
roleDefinitionForLibraryVisitorsGroupOnFolder: string; // each new RFX library has an group created for external users. What role should that group have on trghe site (READ)
roleDefinitionForFolderMembersOnFolder: string; // each new RFX library has an group created for external users. What role should that group have on trghe site (READ)
roleDefinitionForFolderMembersOnLibrary: string; // each new RFX library has an group created for external users. What role should that group have on trghe site (READ)
roleDefinitionForFolderMembersOnSite: string; // each new RFX library has an group created for external users. What role should that group have on trghe site (READ)
roleDefinitionForFolderVisitorsOnFolder: string; // each new RFX library has an group created for external users. What role should that group have on trghe site (READ)
roleDefinitionForFolderVisitorsOnLibrary: string; // each new RFX library has an group created for external users. What role should that group have on trghe site (READ)
roleDefinitionForFolderVisitorsOnSite: string; // each new RFX library has an group created for external users. What role should that group have on trghe site (READ)
allowGroupNameChanges: boolean;
}
export default class RequestMaintenanceWebPart extends BaseClientSideWebPart<IRequestMaintenanceWebPartProps> {
private vistorsGroup: ISiteGroupInfo;
private ownersGroup: ISiteGroupInfo;
private membersGroup: ISiteGroupInfo;
private roleDefinitions: IRoleDefinitionInfo[];
private roleDefinitionsDropdownDisabled: boolean;
// private currentUser:ISiteUser;
public render(): void {
const element: React.ReactElement<IRequestMaintenanceProps> = React.createElement(
RequestMaintenance,
{
siteOwnersGroup: this.ownersGroup, // Site owners groupw will be given full contyrol on new libraros
rfxListTitle: this.properties.rfxListTitle, // the name of the list that holds all the RFX Info
rfxFoldersListTitle: this.properties.rfxFoldersListTitle, // the name of the list that holds all the RFX Info
webServerRelativeUrl: this.context.pageContext.web.serverRelativeUrl,
archiveLibraryTitle: this.properties.archiveLibraryTitle,
enablePrivateFolders: this.properties.enablePrivateFolders,
roleDefinitions: this.roleDefinitions,
roleDefinitionForLibraryMembersGroupOnSite: this.properties.roleDefinitionForLibraryMembersGroupOnSite, // each new RFX library has an group created for internal users. What role should that group have on trghe site (READ)
roleDefinitionForLibraryMembersGroupOnLibrary: this.properties.roleDefinitionForLibraryMembersGroupOnLibrary,// each new RFX library has an group created for internal users. What role should that group have on trghe library (Contribute)
roleDefinitionForLibraryMembersGroupOnFolder: this.properties.roleDefinitionForLibraryMembersGroupOnFolder,// each new RFX library has an group created for internal users. What role should that group have on trghe library (Contribute)
roleDefinitionForLibraryVisitorsGroupOnSite: this.properties.roleDefinitionForLibraryVisitorsGroupOnSite, // each new RFX library has an group created for external users. What role should that group have on trghe site (READ)
roleDefinitionForLibraryVisitorsGroupOnLibrary: this.properties.roleDefinitionForLibraryVisitorsGroupOnLibrary,// each new RFX library has an group created for external users. What role should that group have on trghe library (Contribute)
roleDefinitionForLibraryVisitorsGroupOnFolder: this.properties.roleDefinitionForLibraryVisitorsGroupOnFolder,// each new RFX library has an group created for external users. What role should that group have on trghe library (Contribute)
roleDefinitionForFolderVisitorsOnFolder: this.properties.roleDefinitionForFolderVisitorsOnFolder, // each new RFX library has an group created for external users. What role should that group have on trghe site (READ)
roleDefinitionForFolderVisitorsOnLibrary: this.properties.roleDefinitionForFolderVisitorsOnLibrary, // each new RFX library has an group created for external users. What role should that group have on trghe site (READ)
roleDefinitionForFolderVisitorsOnSite: this.properties.roleDefinitionForFolderVisitorsOnSite, // each new RFX library has an group created for external users. What role should that group have on trghe site (READ)
roleDefinitionForFolderMembersOnFolder: this.properties.roleDefinitionForFolderMembersOnFolder, // each new RFX library has an group created for external users. What role should that group have on trghe site (READ)
roleDefinitionForFolderMembersOnLibrary: this.properties.roleDefinitionForFolderMembersOnLibrary,
roleDefinitionForFolderMembersOnSite: this.properties.roleDefinitionForFolderMembersOnSite,
allowGroupNameChanges: this.properties.allowGroupNameChanges
}
);
ReactDom.render(element, this.domElement);
}
protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement);
}
public onInit(): Promise<any> {
//sessionStorage.setItem("spfx-debug", ""); //// REMOVE THIS
return super.onInit().then(_ => {
pnpSetup({
spfxContext: this.context
});
Logger.activeLogLevel = LogLevel.Warning;
Logger.subscribe(new ConsoleListener());
if (this.properties.instrumentationKey) {
Logger.subscribe(new CustomListener(this.properties.instrumentationKey));
}
let groupsPromise = this.getGroups();
let roledefPromise = this.getRoleDefinitions();
return Promise.all([groupsPromise, roledefPromise]);
});
}
public getRoleDefinitions(): Promise<void> {
return sp.site.rootWeb.roleDefinitions.get().then((rds) => {
this.roleDefinitions = rds;
});
}
public getGroups(): Promise<any> {
let promises: Array<Promise<any>> = [];
promises.push(sp.web.associatedVisitorGroup()
.then((g) => {
this.vistorsGroup = g;
})
.catch((e) => {
debugger;
}));
// Gets the associated members group of a web
promises.push(sp.web.associatedMemberGroup()
.then((g) => {
this.membersGroup = g;
})
.catch((e) => {
debugger;
}));
// Gets the associated owners group of a web
promises.push(sp.web.associatedOwnerGroup()
.then((g) => {
this.ownersGroup = g;
})
.catch((e) => {
debugger;
}));
return Promise.all(promises);
}
protected onPropertyPaneConfigurationStart(): void {
if (this.roleDefinitions) { return; }
this.getRoleDefinitions().then((e) => {
this.roleDefinitionsDropdownDisabled = false;
this.context.propertyPane.refresh();
});
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('rfxListTitle', {
label: strings.rfxListTitleLabel
}),
PropertyPaneTextField('rfxFoldersListTitle', {
label: strings.rfxFoldersListTitleLabel
}),
PropertyPaneTextField('archiveLibraryTitle', {
label: strings.archiveLibraryTitle
}),
PropertyPaneDropdown('roleDefinitionForLibraryMembersGroupOnSite', {
label: strings.roleDefinitionForLibraryMembersGroupOnSite,
options: this.roleDefinitions.map((rd) => {
return { key: rd.Name, text: rd.Name };
}),
}),
PropertyPaneDropdown('roleDefinitionForLibraryMembersGroupOnLibrary', {
label: strings.roleDefinitionForLibraryMembersGroupOnLibrary,
options: this.roleDefinitions.map((rd) => {
return { key: rd.Name, text: rd.Name };
}),
}),
PropertyPaneDropdown('roleDefinitionForLibraryMembersGroupOnFolder', {
label: strings.roleDefinitionForLibraryMembersGroupOnFolder,
options: this.roleDefinitions.map((rd) => {
return { key: rd.Name, text: rd.Name };
}),
}),
PropertyPaneDropdown('roleDefinitionForLibraryVisitorsGroupOnSite', {
label: strings.roleDefinitionForLibraryVisitorsGroupOnSite,
options: this.roleDefinitions.map((rd) => {
return { key: rd.Name, text: rd.Name };
}),
}),
PropertyPaneDropdown('roleDefinitionForLibraryVisitorsGroupOnLibrary', {
label: strings.roleDefinitionForLibraryVisitorsGroupOnLibrary,
options: this.roleDefinitions.map((rd) => {
return { key: rd.Name, text: rd.Name };
}),
}),
PropertyPaneDropdown('roleDefinitionForLibraryVisitorsGroupOnFolder', {
label: strings.roleDefinitionForLibraryVisitorsGroupOnFolder,
options: this.roleDefinitions.map((rd) => {
return { key: rd.Name, text: rd.Name };
}),
}),
PropertyPaneDropdown('roleDefinitionForFolderMembersOnSite', {
label: strings.roleDefinitionForFolderMembersOnSite,
options: this.roleDefinitions.map((rd) => {
return { key: rd.Name, text: rd.Name };
}),
}),
PropertyPaneDropdown('roleDefinitionForFolderMembersOnLibrary', {
label: strings.roleDefinitionForFolderMembersOnLibrary,
options: this.roleDefinitions.map((rd) => {
return { key: rd.Name, text: rd.Name };
}),
}),
PropertyPaneDropdown('roleDefinitionForFolderMembersOnFolder', {
label: strings.roleDefinitionForFolderMembersOnFolder,
options: this.roleDefinitions.map((rd) => {
return { key: rd.Name, text: rd.Name };
}),
}),
PropertyPaneDropdown('roleDefinitionForFolderVisitorsOnSite', {
label: strings.roleDefinitionForFolderVisitorsOnSite,
options: this.roleDefinitions.map((rd) => {
return { key: rd.Name, text: rd.Name };
}),
}),
PropertyPaneDropdown('roleDefinitionForFolderVisitorsOnLibrary', {
label: strings.roleDefinitionForFolderVisitorsOnLibrary,
options: this.roleDefinitions.map((rd) => {
return { key: rd.Name, text: rd.Name };
}),
}),
PropertyPaneDropdown('roleDefinitionForFolderVisitorsOnFolder', {
label: strings.roleDefinitionForFolderVisitorsOnFolder,
options: this.roleDefinitions.map((rd) => {
return { key: rd.Name, text: rd.Name };
}),
}),
PropertyPaneToggle('allowGroupNameChanges', {
label: strings.allowGroupNameChanges,
}),
PropertyPaneToggle('enablePrivateFolders', {
label:strings.privateFolders,
offText:strings.privateFoldersDisabled,
onText: strings.privateFoldersEnabled,
}),
PropertyPaneTextField('instrumentationKey', {
label: strings.instrumentationKey
}),
]
}
]
}
]
};
}
}

View File

@ -0,0 +1,39 @@
import { ISiteGroupInfo } from "@pnp/sp/site-groups";
import { IRoleDefinition, IRoleDefinitionInfo } from '@pnp/sp/security';
import { ISiteUser } from "@pnp/sp/site-users";
import { SPHttpClient, SPHttpClientResponse, SPHttpClientConfiguration } from '@microsoft/sp-http';
export interface IRequestMaintenanceProps {
siteOwnersGroup:ISiteGroupInfo; // Site owners groupw will be given full contyrol on new libraros
rfxListTitle:string; // the name of the list that holds all the RFX Info
rfxFoldersListTitle:string; // the name of the list that holds all the RFX Folder Info
archiveLibraryTitle:string; // the name of the library that ther archive button moves stuff to.
webServerRelativeUrl:string;
roleDefinitions:Array<IRoleDefinitionInfo>;// all role definitions on the site
roleDefinitionForLibraryMembersGroupOnLibrary:string;// each new RFX library has an group created for internal users. What role should that group have on trghe library (Contribute)
roleDefinitionForLibraryMembersGroupOnSite: string; // each new RFX library has an group created for internal users. What role should that group have on trghe site (READ)
roleDefinitionForLibraryMembersGroupOnFolder: string; // each new RFX library has an group created for internal users. What role should that group have on trghe site (READ)
roleDefinitionForLibraryVisitorsGroupOnLibrary:string;// each new RFX library has an group created for external users. What role should that group have on trghe library (Contribute)
roleDefinitionForLibraryVisitorsGroupOnSite: string; // each new RFX library has an group created for external users. What role should that group have on trghe site (READ)
roleDefinitionForLibraryVisitorsGroupOnFolder: string; // each new RFX library has an group created for external users. What role should that group have on trghe site (READ)
roleDefinitionForFolderMembersOnFolder:string;
roleDefinitionForFolderMembersOnLibrary:string;
roleDefinitionForFolderMembersOnSite:string;
roleDefinitionForFolderVisitorsOnFolder:string;
roleDefinitionForFolderVisitorsOnLibrary:string;
roleDefinitionForFolderVisitorsOnSite:string;
allowGroupNameChanges:boolean;
enablePrivateFolders:boolean;
}

View File

@ -0,0 +1,37 @@
import { ISiteGroupInfo } from "@pnp/sp/site-groups";
import { IRoleDefinition, IRoleDefinitionInfo } from '@pnp/sp/security';
import { IRFx } from '../../../models/IRFx';
import { IRFxFolder } from '../../../models/IRFxFolder';
import { IActivity } from '../../../models/IActivity';
import { ISiteUser } from "@pnp/sp/site-users";
export interface IRequestMaintenanceState {
currentUserId: number;
currentUserEMail: string;
currentUserLoginName: string;
selectedRfx: IRFx;
showFolders: boolean;
rfxFolders:Array<IRFxFolder>;
rfxs: Array<IRFx>;
siteGroups: ISiteGroupInfo[];
showAddNewLibrary: boolean;
isUpdating: boolean;
invalidCharacters: boolean;
// used when adding an rfx::
newRfxId: string;
newRfxDescription: string;
newRFxClosingDate: Date;
newRFxLibraryMembersGroupName: string;
newRFxLibraryVisitorsGroupName: string;
newRFxLibraryOwnersGroupName: string;
showAddNewFolder: boolean;
newFolderName:string;
newFolderMembersGroupName:string;
newFolderVisitorsGroupName:string;
showActivity:boolean;
activities:Array<IActivity>;
mainSelectedItemsCount:number;
}

View File

@ -0,0 +1,67 @@
@import '~office-ui-fabric-react/dist/sass/References.scss';
.requestMaintenance {
.container {
max-width: 700px;
margin: 0px auto;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
.row {
@include ms-Grid-row;
@include ms-fontColor-white;
background-color: $ms-color-themeDark;
padding: 20px;
}
.column {
@include ms-Grid-col;
@include ms-lg10;
@include ms-xl8;
@include ms-xlPush2;
@include ms-lgPush1;
}
.title {
@include ms-font-xl;
@include ms-fontColor-white;
}
.subTitle {
@include ms-font-l;
@include ms-fontColor-white;
}
.description {
@include ms-font-l;
@include ms-fontColor-white;
}
.commandBar button {
border-width: 0px;
}
.button {
// Our button
text-decoration: none;
height: 3200px;
// Primary Button
min-width: 80px;
background-color: $ms-color-themePrimary;
border-color: $ms-color-themePrimary;
color: $ms-color-white;
// Basic Button
outline: transparent;
position: relative;
font-family: "Segoe UI WestEuropean", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif;
-webkit-font-smoothing: antialiased;
font-size: $ms-font-size-m;
font-weight: $ms-font-weight-regular;
border-width: 0;
text-align: center;
cursor: pointer;
display: inline-block;
padding: 0 16px;
.label {
font-weight: $ms-font-weight-semibold;
font-size: $ms-font-size-m;
height: 32px;
line-height: 32px;
margin: 0 4px;
vertical-align: top;
display: inline-block;
}
}
}

View File

@ -0,0 +1,32 @@
define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"instrumentationKey": "App Insights instrumentation key",
"privateFoldersEnabled": "Private folders enabled",
"privateFoldersDisabled": "Private folders enabled",
"privateFolders": "Private Folders",
"rfxListTitleLabel": "RFX List",
"rfxFoldersListTitleLabel": "RFX Folders List",
"roleDefinitionForLibraryMembersGroupOnLibrary": "Permission for library members on Libraries",
"roleDefinitionForLibraryMembersGroupOnSite": "Permission for library members on Site",
"roleDefinitionForLibraryMembersGroupOnFolder": "Permission for library members on Folders",
"roleDefinitionForLibraryVisitorsGroupOnLibrary": "Permission for library visitors on Libraries",
"roleDefinitionForLibraryVisitorsGroupOnSite": "Permission for library visitors on Site",
"roleDefinitionForLibraryVisitorsGroupOnFolder": "Permission for library visitors on Folders",
"roleDefinitionForFolderMembersOnFolder": "Permission for Folder members on Folders",
"roleDefinitionForFolderMembersOnLibrary": "Permission for Folder members on Library",
"roleDefinitionForFolderMembersOnSite": "Permission for Folder members on Site",
"roleDefinitionForFolderVisitorsOnFolder": "Permission for Folder visitors on Folders",
"roleDefinitionForFolderVisitorsOnLibrary": "Permission for Folder visitors on Library",
"roleDefinitionForFolderVisitorsOnSite": "Permission for Folder visitors on Site",
"allowGroupNameChanges": "Allow users to change generated security group names",
"archiveLibraryTitle": "Archive Library"
}
});

View File

@ -0,0 +1,37 @@
declare interface IRequestMaintenanceWebPartStrings {
instrumentationKey:string;
PropertyPaneDescription: string;
BasicGroupName: string;
rfxListTitleLabel:string;
rfxFoldersListTitleLabel:string;
archiveLibraryTitle:string;
privateFoldersEnabled:string;
privateFoldersDisabled:string;
privateFolders:string;
// Library member permissions
roleDefinitionForLibraryMembersGroupOnLibrary:string;
roleDefinitionForLibraryMembersGroupOnSite:string;
roleDefinitionForLibraryMembersGroupOnFolder:string;
// library visitor permissions
roleDefinitionForLibraryVisitorsGroupOnLibrary:string;
roleDefinitionForLibraryVisitorsGroupOnSite:string;
roleDefinitionForLibraryVisitorsGroupOnFolder:string;
// folder member permissions
roleDefinitionForFolderMembersOnFolder:string;
roleDefinitionForFolderMembersOnLibrary:string;
roleDefinitionForFolderMembersOnSite:string;
roleDefinitionForFolderVisitorsOnFolder:string;
roleDefinitionForFolderVisitorsOnLibrary:string;
roleDefinitionForFolderVisitorsOnSite:string;
allowGroupNameChanges:string;
}
declare module 'RequestMaintenanceWebPartStrings' {
const strings: IRequestMaintenanceWebPartStrings;
export = strings;
}

View File

@ -0,0 +1,27 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "dca49132-f256-4f99-8509-864d663d4d3b",
"alias": "VendorMaintenanceWebPart",
"componentType": "WebPart",
// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2,
// If true, the component can only be installed on sites where Custom Script is allowed.
// Components that allow authors to embed arbitrary script code should set this to true.
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
"requiresCustomScript": false,
"supportedHosts": ["SharePointWebPart"],
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other" },
"title": { "default": "VendorMaintenance" },
"description": { "default": "VendorMaintenance description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "VendorMaintenance"
}
}]
}

View File

@ -0,0 +1,152 @@
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '@microsoft/sp-core-library';
import {
IPropertyPaneConfiguration,
PropertyPaneTextField, PropertyPaneDropdown, IPropertyPaneDropdownOption
} from '@microsoft/sp-property-pane';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import * as strings from 'VendorMaintenanceWebPartStrings';
import VendorMaintenance from './components/VendorMaintenance';
import { IVendorMaintenanceProps } from './components/IVendorMaintenanceProps';
import { ISiteGroupInfo } from '@pnp/sp/site-groups';
export interface IVendorMaintenanceWebPartProps {
ownersGroup: string;
roleDefinitionForSite: string;
}
import { setup as pnpSetup } from "@pnp/common";
import { sp } from "@pnp/sp";
import "@pnp/sp/site-groups/web";
import "@pnp/sp/webs";
import "@pnp/sp/site-groups/web";
import "@pnp/sp/security";
import { IRoleDefinitionInfo } from '@pnp/sp/security';
import { SPHttpClient, SPHttpClientResponse, SPHttpClientConfiguration } from '@microsoft/sp-http';
export default class VendorMaintenanceWebPart extends BaseClientSideWebPart<IVendorMaintenanceWebPartProps> {
private vistorsGroup: ISiteGroupInfo;
private ownersGroup: ISiteGroupInfo;
private membersGroup: ISiteGroupInfo;
private roleDefinitions: IRoleDefinitionInfo[];
private roleDefinitionsDropdownDisabled: boolean = true;
public onInit(): Promise<any> {
debugger;
//sessionStorage.setItem("spfx-debug", ""); //// REMOVE THIS
return super.onInit().then(_ => {
pnpSetup({
spfxContext: this.context
});
let groupsPromise = this.getGroups();
let roledefPromise = this.getRoleDefinitions();
return Promise.all([groupsPromise, roledefPromise]);
});
}
public getGroups(): Promise<any> {
let promises: Array<Promise<any>> = [];
promises.push(sp.web.associatedVisitorGroup()
.then((g) => {
this.vistorsGroup = g;
})
.catch((e) => {
debugger;
}));
// Gets the associated members group of a web
promises.push(sp.web.associatedMemberGroup()
.then((g) => {
this.membersGroup = g;
})
.catch((e) => {
debugger;
}));
// Gets the associated owners group of a web
promises.push(sp.web.associatedOwnerGroup()
.then((g) => {
this.ownersGroup = g;
})
.catch((e) => {
debugger;
}));
return Promise.all(promises);
}
public getRoleDefinitions(): Promise<void> {
return sp.site.rootWeb.roleDefinitions.get().then((rds) => {
this.roleDefinitions = rds;
});
}
public render(): void {
const element: React.ReactElement<IVendorMaintenanceProps> = React.createElement(
VendorMaintenance,
{
roleDefinitionForSite: this.properties.roleDefinitionForSite,
ownersGroup: this.ownersGroup,
webServerRelativeUrl: this.context.pageContext.web.serverRelativeUrl,
vendorListTitle: "Vendors",
roleDefinitions: this.roleDefinitions
}
);
ReactDom.render(element, this.domElement);
}
protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement);
}
protected onPropertyPaneConfigurationStart(): void {
debugger;
if (this.roleDefinitions) { return; }
this.getRoleDefinitions().then((e) => {
this.roleDefinitionsDropdownDisabled = false;
this.context.propertyPane.refresh();
});
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneDropdown('roleDefinitionForSite', {
label: strings.roleDefinitionForSiteLabel,
options: this.roleDefinitions.map((rd) => {
debugger;
return { key: rd.Name, text: rd.Name };
}),
}),
PropertyPaneTextField('ownersGroup', {
label: strings.ownersGroupLabel
})
]
}
]
}
]
};
}
}

View File

@ -0,0 +1,9 @@
import { ISiteGroupInfo } from "@pnp/sp/site-groups";
import { IRoleDefinition, IRoleDefinitionInfo } from '@pnp/sp/security';
export interface IVendorMaintenanceProps {
ownersGroup:ISiteGroupInfo;
vendorListTitle:string;
webServerRelativeUrl:string;
roleDefinitionForSite: string; //role to give new groups in the site
roleDefinitions:Array<IRoleDefinitionInfo>;
}

View File

@ -0,0 +1,10 @@
import { ISiteGroupInfo } from "@pnp/sp/site-groups";
import { IVendor } from '../../../models/IVendor';
export interface IVendorMaintenanceState {
vendors: Array<IVendor>;
newVendorTitle:string;
newVendorGroupName:string;
showAddNew:boolean;
isUpdating:boolean; //disable save button while update in progress
}

View File

@ -0,0 +1,74 @@
@import '~office-ui-fabric-react/dist/sass/References.scss';
.vendorMaintenance {
.container {
max-width: 700px;
margin: 0px auto;
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
.row {
@include ms-Grid-row;
@include ms-fontColor-white;
background-color: $ms-color-themeDark;
padding: 20px;
}
.column {
@include ms-Grid-col;
@include ms-lg10;
@include ms-xl8;
@include ms-xlPush2;
@include ms-lgPush1;
}
.title {
@include ms-font-xl;
@include ms-fontColor-white;
}
.subTitle {
@include ms-font-l;
@include ms-fontColor-white;
}
.description {
@include ms-font-l;
@include ms-fontColor-white;
}
.button {
// Our button
text-decoration: none;
height: 32px;
// Primary Button
min-width: 80px;
background-color: $ms-color-themePrimary;
border-color: $ms-color-themePrimary;
color: $ms-color-white;
// Basic Button
outline: transparent;
position: relative;
font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif;
-webkit-font-smoothing: antialiased;
font-size: $ms-font-size-m;
font-weight: $ms-font-weight-regular;
border-width: 0;
text-align: center;
cursor: pointer;
display: inline-block;
padding: 0 16px;
.label {
font-weight: $ms-font-weight-semibold;
font-size: $ms-font-size-m;
height: 32px;
line-height: 32px;
margin: 0 4px;
vertical-align: top;
display: inline-block;
}
}
}

View File

@ -0,0 +1,215 @@
import * as React from 'react';
import { sp, SPHttpClient } from "@pnp/sp";
import "@pnp/sp/webs";
import "@pnp/sp/sites";
import "@pnp/sp/site-groups";
import "@pnp/sp/lists/web";
import "@pnp/sp/lists/web";
import "@pnp/sp/items";
import "@pnp/sp/security/list";
import "@pnp/sp/security/web";
import "@pnp/sp/folders";
import "@pnp/sp/views";
import { DetailsList } from 'office-ui-fabric-react/lib/DetailsList';
import { Label } from 'office-ui-fabric-react/lib/Label';
import { PrimaryButton, Button } from 'office-ui-fabric-react/lib/Button';
import { TextField } from 'office-ui-fabric-react/lib/TextField';
import { Panel } from 'office-ui-fabric-react/lib/Panel';
import { Link } from 'office-ui-fabric-react/lib/Link';
import { ISiteGroupInfo } from '@pnp/sp/site-groups';
import { autobind } from 'office-ui-fabric-react/lib/Utilities';
import { IViewInfo } from '@pnp/sp/views';
import { IRoleDefinitionInfo } from '@pnp/sp/security';
import styles from './VendorMaintenance.module.scss';
import { IVendorMaintenanceProps } from './IVendorMaintenanceProps';
import { IVendorMaintenanceState } from './IVendorMaintenanceState';
import { escape } from '@microsoft/sp-lodash-subset';
import { IVendor } from '../../../models/IVendor';
import RFXUtilities from '../../../utilities/RFXUtilities';
export default class VendorMaintenance extends React.Component<IVendorMaintenanceProps, IVendorMaintenanceState> {
public state = {
vendors: [],
showAddNew: false,
newVendorTitle: null,
newVendorGroupName: null,
isUpdating: false,
invalidCharacters: false
};
public componentDidMount() {
this.fetchVendors();
}
/**
* Fetches the list of vendors (store in a sharepoint list) and updates them in the docLibs State varieble
*
* @private
* @memberof DocLibSecurity
*/
private fetchVendors() {
sp.web.lists.getByTitle(this.props.vendorListTitle).items.orderBy("Title").get().then((items) => {
this.setState((current) => ({
...current,
vendors: items.map((item) => {
return { title: item.Title, membersGroup: item["SecurityGroup"], id: item.Id };
})
})
);
});
}
/**
* Validates the data to add a new vendor and adds it if valid
*
* @private
* @returns
* @memberof DocLibSecurity
*/
private async validateAndAddVendor() {
debugger;
this.setState((current) => ({ ...current, isUpdating: true }));
//Do validation
let groupExists = await RFXUtilities.doesGroupExist(this.state.newVendorGroupName);
if (groupExists) {
alert("A group with this name already exists");
this.setState((current) => ({ ...current, isUpdating: false }));
return;
}
// Add the new group
await sp.web.siteGroups.add({ "Title": this.state.newVendorGroupName })
.catch((e) => {
alert("there was an error adding the group");
this.setState((current) => ({ ...current, isUpdating: false }));
return;
});
const newGroup = await sp.web.siteGroups.getByName(this.state.newVendorGroupName).get();
// set the groups owner
await RFXUtilities.setGroupOwner(newGroup.Id, this.props.ownersGroup.Id)
.catch((e) => {
alert("there was an setting the owner on the new group");
this.setState((current) => ({ ...current, isUpdating: false }));
return;
});
// await RFXUtilities.grantNewGroupAccessToSite(this.state.newVendorGroupName, this.props.roleDefinitionForSite,this.props.roleDefinitions).catch((e) => {
// alert("there was an error granting access to the site to the new group");
// this.setState((current) => ({ ...current, isUpdating: false }));
// return;
// });
debugger;
// add an entry to the Secured Libraries list to track this entry
await sp.web.lists.getByTitle(this.props.vendorListTitle).items.add({
Title: this.state.newVendorTitle,
SecurityGroup: this.state.newVendorGroupName
})
.catch((e) => {
alert("there was an updating the List of Libraries");
this.setState((current) => ({ ...current, isUpdating: false }));
return;
});
this.fetchVendors();
this.setState((current) => ({ ...current, showAddNew: false, isUpdating: false, newVendorGroupName: "", newVendorTitle: "" }));
}
private async deleteVendor(item: IVendor) {
this.setState((current) => ({ ...current, isUpdating: true }));
//Do validation
let groupExists = await RFXUtilities.doesGroupExist(item.membersGroup);
if (!groupExists) {
alert("A group with this name does not exist ");
this.setState((current) => ({ ...current, isUpdating: false }));
return;
}
await RFXUtilities.deletegroup(item.membersGroup)
.catch((e) => {
alert("there was an error deleting the group");
this.setState((current) => ({ ...current, isUpdating: false }));
return;
});
// await RFXUtilities.deleterow(item.id,this.props.vendorListTitle)
// .catch((e) => {
// alert("there was an removing the row from the vendors list");
// this.setState((current) => ({ ...current, isUpdating: false }));
// return;
// });
this.fetchVendors();
this.setState((current) => ({ ...current, showAddNew: false, isUpdating: false, newVendorGroupName: "", newVendorTitle: "" }));
}
public render(): React.ReactElement<IVendorMaintenanceProps> {
return (
<div className={styles.vendorMaintenance}>
<Panel isOpen={this.state.showAddNew} >
<TextField label="Vendor Name" placeholder="enter vendor name" value={this.state.newVendorTitle} onChange={(e, value) => {
this.setState((current) => ({
...current,
newVendorTitle: value.replace(/[&\/\\#,+()$~% "`:;*?<>{}|^!@$']/g, ''),
newVendorGroupName: value.replace(/[&\/\\#,+()$~% "`:;*?<>{}|^!@$']/g, '') + " Members"
}));
}}></TextField>
<TextField label="Group Name" placeholder="enter group name" value={this.state.newVendorGroupName}
default={this.state.newVendorGroupName} onChange={(e, value) => {
this.setState((current) => ({ ...current, newVendorGroupName: value.replace(/[&\/\\#,+()$~% "`:;*?<>{}|^!@$']/g, '') }));
}}></TextField>
<PrimaryButton disabled={this.state.isUpdating || this.state.invalidCharacters} onClick={(e) => {
this.validateAndAddVendor();
}}>Add Vendor</PrimaryButton>
</Panel>
<DetailsList
items={this.state.vendors}
columns={[
{
key: 'column1', name: 'Vendor Name', fieldName: 'title', minWidth: 100, maxWidth: 200, isResizable: true,
onRender: (item: IVendor) => (
<Label>{item.title}</Label>
)
},
{
key: 'column3', name: 'Security Group', fieldName: 'membersGroup', minWidth: 100, maxWidth: 200, isResizable: true,
onRender: (item: IVendor) => (
<Link onClick={() => {
RFXUtilities.linkToGroup(item.membersGroup, this.props.webServerRelativeUrl);
}}>{item.membersGroup}</Link>
)
},
{
key: 'edit', name: 'Edit', fieldName: 'edit', minWidth: 100, maxWidth: 200, isResizable: false,
onRender: (item: IVendor) => (
<Link onClick={() => {
this.deleteVendor(item);
}}>Delete</Link>
)
}
]}
>
</DetailsList>
<Button onClick={(e) => this.setState((current) => ({ ...current, showAddNew: true, newVendorGroupName: "", newVendorTitle: "" }))}>Add new Vendor</Button>
</div>
);
}
}

View File

@ -0,0 +1,7 @@
define([], function() {
return {
"roleDefinitionForSiteLabel": "Role def users get on site",
"ownersGroupLabel": "group that owns the groups"
}
});

View File

@ -0,0 +1,12 @@
declare interface IVendorMaintenanceWebPartStrings {
PropertyPaneDescription: string;
BasicGroupName: string;
roleDefinitionForSiteLabel: string;
ownersGroupLabel: string;
}
declare module 'VendorMaintenanceWebPartStrings' {
const strings: IVendorMaintenanceWebPartStrings;
export = strings;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,38 @@
{
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.3/includes/tsconfig-web.json",
"compilerOptions": {
"target": "es5",
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"jsx": "react",
"declaration": true,
"sourceMap": true,
"experimentalDecorators": true,
"skipLibCheck": true,
"outDir": "lib",
"inlineSources": false,
"strictNullChecks": false,
"noUnusedLocals": false,
"typeRoots": [
"./node_modules/@types",
"./node_modules/@microsoft"
],
"types": [
"es6-promise",
"webpack-env"
],
"lib": [
"es5",
"dom",
"es2015.collection"
]
},
"include": [
"src/**/*.ts"
],
"exclude": [
"node_modules",
"lib"
]
}

View File

@ -0,0 +1,30 @@
{
"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
}
}

View File

@ -1,6 +1,6 @@
{ {
"name": "react-simple-poll", "name": "react-simple-poll",
"version": "0.0.1", "version": "2.1.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {