+ {/*
+
+ ADD NEW LIBRARY PANEL
+
+ */}
+ {this.state.showAddNewLibrary &&
+
{
+ this.setState((current) => ({ ...current, showAddNewLibrary: false }));
+ }}
+ type={PanelType.medium}
+ headerText={`Add a new Library`}
+ >
+ {
+ this.setState((current) => ({
+ ...current,
+ newRfxId: value.replace(/[&\/\\#,+()$~% "`:;*?<>{}|^!@$']/g, ''),
+ newRFxOwnersGroupName: value.replace(/[&\/\\#,+()$~% "`:;*?<>{}|^!@$']/g, '') + " Owners",
+ newRFxLibraryMembersGroupName: value.replace(/[&\/\\#,+()$~% "`:;*?<>{}|^!@$']/g, '') + " Members",
+ newRFxLibraryVisitorsGroupName: value.replace(/[&\/\\#,+()$~% "`:;*?<>{}|^!@$']/g, '') + " Visitors",
+ newRFxLibraryOwnersGroupName: value.replace(/[&\/\\#,+()$~% "`:;*?<>{}|^!@$']/g, '') + " Owners",
+
+ }));
+ }} />
+ {
+ this.setState((current) => ({ ...current, newRFxClosingDate: date }));
+ }} />
+ {
+ this.setState((current) => ({ ...current, newRfxDescription: value }));
+ }} />
+
+ {
+ this.setState((current) => ({ ...current, newRFxLibraryOwnersGroupName: value.replace(/[&\/\\#,+()$~% "`:;*?<>{}|^!@$']/g, '') }));
+ }} />
+ {
+ this.setState((current) => ({ ...current, newRFxLibraryMembersGroupName: value.replace(/[&\/\\#,+()$~% "`:;*?<>{}|^!@$']/g, '') }));
+ }} />
+ {
+ this.setState((current) => ({ ...current, newRFxLibraryVisitorsGroupName: value.replace(/[&\/\\#,+()$~% "`:;*?<>{}|^!@$']/g, '') }));
+ }} />
+
+ {
+ this.validateAndAddLibrary();
+ }}>Add Library
+
+ }
+ {/*
+
+ ADD NEW FOLDER PANEL
+
+ */}
+
+ {this.state.showAddNewFolder &&
+
{
+
+ this.setState((current) => ({ ...current, showAddNewFolder: false }));
+ }}
+ type={PanelType.medium}
+ headerText={`Add a Folder to Library ${this.state.selectedRfx.title}`}
+ >
+ {
+ this.setState((current) => ({
+ ...current,
+ newFolderName: value.replace(/[\x5B&\/\\#,+()$~% "`:;*?<>{}|^!@$']/g, ''),
+ newFolderMembersGroupName: this.state.selectedRfx.title + " - " + value.replace(/[&\/\\#,+()$~% "`:;*?<>{}|^!@$']/g, '') + " Members",
+ newFolderVisitorsGroupName: this.state.selectedRfx.title + " - " + value.replace(/[&\/\\#,+()$~% "`:;*?<>{}|^!@$']/g, '') + " Visitors",
+ }));
+ }} />
+ {
+ this.setState((current) => ({
+ ...current,
+ newFolderMembersGroupName: value.replace(/[&\/\\#,+()$~% "`:;*?<>{}|^!@$']/g, '')
+ }));
+ }} />
+ {
+ this.setState((current) => ({
+ ...current,
+ newFolderVisitorsGroupName: value.replace(/[&\/\\#,+()$~% "`:;*?<>{}|^!@$']/g, '')
+ }));
+ }} />
+
+ {
+ this.validateAndAddFolder();
+ }}>Add Folder
+
+ }
+
+ {/*
+
+ Show FOLDERs PANEL
+
+ */}
+ {(this.state.showFolders && !this.state.showAddNewFolder) &&
+
{
+ this.setState((current) => ({ ...current, showFolders: false }));
+ }}
+ headerText={`Folders for Rfx ${this.state.selectedRfx.title}`}
+ >
+ (
+ {
+ RFXUtilities.linkToFolder(item, this.props.rfxListTitle);
+ }}>{item.title}
+ )
+ },
+
+ {
+ key: 'column5', name: 'Members Group', fieldName: 'folderMembersGroupId', minWidth: 100, maxWidth: 200, isResizable: true,
+ onRender: (item: IRFxFolder) => (
+
+ {
+ RFXUtilities.linkToGroupById(item.folderMembersGroupId, this.props.webServerRelativeUrl);
+ }}>{this.getSiteGroupName(item.folderMembersGroupId)}
+ )
+ },
+ {
+ key: 'column5', name: 'Visitors Group', fieldName: 'folderVisitorsGroupId', minWidth: 100, maxWidth: 200, isResizable: true,
+ onRender: (item: IRFxFolder) => (
+
+ {
+ RFXUtilities.linkToGroupById(item.folderVisitorsGroupId, this.props.webServerRelativeUrl);
+ }}>{this.getSiteGroupName(item.folderVisitorsGroupId)}
+ )
+ },
+ {
+ key: 'edit', name: ' ', fieldName: 'edit', minWidth: 50, maxWidth: 50, isResizable: false,
+ onRender: (item: IRFxFolder) => (
+ {
+ if (!this.state.isUpdating) {
+ if (window.confirm(`Are you sure you want to delete folder ${item['title']} ?`)) {
+ this.setState((current) => ({ ...current, isUpdating: true }));
+ await this.deleteFolder(item);
+ await this.fetchRFxFolders(this.state.selectedRfx)
+ .then((folders) => {
+ this.setState((current) => ({ ...current, rfxFolders: folders }));
+ })
+ .catch((e) => {
+ const message = `there was an fetching folders for library ${item.title}`;
+
+ this.logError(message, e);
+
+ });
+ this.setState((current) => ({ ...current, isUpdating: false }));
+ }
+
+ }
+
+ }} />
+
+ )
+ },
+ ]}
+ >
+
+ {
+ this.setState((current) => ({ ...current, showAddNewFolder: true, newFolderName: "", newFolderSecurityGroupName: "" }));
+ }
+ }>Add a new Folder
+
+ }
+
+ {/*
+
+ Show Activities PANEL
+
+ */}
+ {(this.state.showActivity) &&
+
{
+ this.setState((current) => ({ ...current, showActivity: false }));
+ }}
+ headerText={`Activity for Rfx ${this.state.selectedRfx.title}`}
+ >
+
+
+
+
+
+ (
+ format(item.activityRecordedTime, "yyyyMMMd@h:m:sa")
+ )
+ },
+ {
+ key: 'driveItemParentReference', name: 'Folder', fieldName: 'driveItemParentReference', minWidth: 200, maxWidth: 200, isResizable: true,
+ onRender: (item: IActivity) => (
+ item.driveItemParentReference.substring(item.driveItemParentReference.indexOf("root:") + 6)
+ )
+ },
+ ]}
+ >
+
+
+
+ }
+
+
+ {/*
+
+ MAIN DISPLAY
+
+ */}
+ {this.state.isUpdating &&
+
Updating...
+ }
+
+
(
+ {
+ RFXUtilities.linkToLibrary(item.title);
+ }}>{item.title}
+ )
+ },
+ // {
+ // key: 'contractSpecialist', name: 'Contract Specialist', fieldName: 'contractSpecialist.EMail', minWidth: 200, maxWidth: 200, isResizable: true,
+ // onRender: (item: IRFx) => (
+ // item.contractSpecialist.EMail
+ // )
+ // },
+ {
+ key: 'closingDate', name: 'Closing Date', fieldName: 'closingDate', minWidth: 100, maxWidth: 100, isResizable: true,
+ onRender: (item: IRFx) => (
+ item.closingDate.toDateString()
+ )
+ },
+ {
+ key: 'description', name: 'Description', fieldName: 'description', minWidth: 100, maxWidth: 400, isResizable: true,
+ onRender: (item: IRFx) => (
+
+ )
+ },
+ {
+ key: 'column4', name: 'Owners', fieldName: 'libraryOwnersGroupId', minWidth: 100, maxWidth: 400, isResizable: true,
+ onRender: (item: IRFx) => (
+ {
+ RFXUtilities.linkToGroupById(item.libraryOwnersGroupId, this.props.webServerRelativeUrl);
+ }}>{this.getSiteGroupName(item.libraryOwnersGroupId)}
+ )
+ },
+ {
+ key: 'column4', name: 'Members', fieldName: 'libraryMembersGroupId', minWidth: 100, maxWidth: 400, isResizable: true,
+ onRender: (item: IRFx) => (
+ {
+ RFXUtilities.linkToGroupById(item.libraryMembersGroupId, this.props.webServerRelativeUrl);
+ }}>{this.getSiteGroupName(item.libraryMembersGroupId)}
+ )
+ },
+ {
+ key: 'column4a', name: 'Visitors', fieldName: 'libraryVisitorsGroupId', minWidth: 100, maxWidth: 400, isResizable: true,
+ onRender: (item: IRFx) => (
+ {
+ RFXUtilities.linkToGroupById(item.libraryVisitorsGroupId, this.props.webServerRelativeUrl);
+ }}>{this.getSiteGroupName(item.libraryVisitorsGroupId)}
+ )
+ },
+
+
+ ]}
+ >
+
+ {/*
{
+ this.setState((current) => ({ ...current, showAddNewLibrary: true, newDocLibGroupName: "", newDocLibTitle: "" }));
+ }
+ }>Add a new RFx library */}
+
+
+
+ );
+ }
+}
diff --git a/samples/react-private-libraries/src/webparts/requestMaintenance/loc/en-us.js b/samples/react-private-libraries/src/webparts/requestMaintenance/loc/en-us.js
new file mode 100644
index 000000000..a6b953611
--- /dev/null
+++ b/samples/react-private-libraries/src/webparts/requestMaintenance/loc/en-us.js
@@ -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"
+
+ }
+});
\ No newline at end of file
diff --git a/samples/react-private-libraries/src/webparts/requestMaintenance/loc/mystrings.d.ts b/samples/react-private-libraries/src/webparts/requestMaintenance/loc/mystrings.d.ts
new file mode 100644
index 000000000..00ac0ca71
--- /dev/null
+++ b/samples/react-private-libraries/src/webparts/requestMaintenance/loc/mystrings.d.ts
@@ -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;
+}
diff --git a/samples/react-private-libraries/src/webparts/vendorMaintenance/VendorMaintenanceWebPart.manifest.json b/samples/react-private-libraries/src/webparts/vendorMaintenance/VendorMaintenanceWebPart.manifest.json
new file mode 100644
index 000000000..08e7180bd
--- /dev/null
+++ b/samples/react-private-libraries/src/webparts/vendorMaintenance/VendorMaintenanceWebPart.manifest.json
@@ -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"
+ }
+ }]
+}
diff --git a/samples/react-private-libraries/src/webparts/vendorMaintenance/VendorMaintenanceWebPart.ts b/samples/react-private-libraries/src/webparts/vendorMaintenance/VendorMaintenanceWebPart.ts
new file mode 100644
index 000000000..5809782c1
--- /dev/null
+++ b/samples/react-private-libraries/src/webparts/vendorMaintenance/VendorMaintenanceWebPart.ts
@@ -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