Merge pull request #1846 from Tanddant/main

This commit is contained in:
Hugo Bernier 2021-05-03 21:35:04 -04:00 committed by GitHub
commit 68e4113213
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 19641 additions and 15 deletions

View File

@ -10,7 +10,6 @@
>
> DELETE THIS PARAGRAPH BEFORE SUBMITTING
## Summary
Short summary on functionality and used technologies.
@ -60,15 +59,6 @@ Short summary on functionality and used technologies.
> Update accordingly as needed.
> DELETE THIS PARAGRAPH BEFORE SUBMITTING
## Prerequisites
> Any special pre-requisites? Include any lists, permissions, offerings to the demo gods, or whatever else needs to be done for this web part to work.
>
> Please describe the steps to configure the pre-requisites. Feel free to add screen shots, but make sure that there is a text description of the steps to perform.
>
> DELETE THE TEXT ABOVE BEFORE SUBMITTING
## Solution
> We use this section to recognize and promote your contributions. Please provide one author per line -- even if you worked together on it.
@ -89,11 +79,13 @@ Version|Date|Comments
1.1|September 2, 2021|Update comment
1.0|August 29, 2021|Initial release
## Disclaimer
## Prerequisites
**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.**
---
> Any special pre-requisites? Include any lists, permissions, offerings to the demo gods, or whatever else needs to be done for this web part to work.
>
> Please describe the steps to configure the pre-requisites. Feel free to add screen shots, but make sure that there is a text description of the steps to perform.
>
> DELETE THE TEXT ABOVE BEFORE SUBMITTING
## Minimal Path to Awesome
@ -117,4 +109,18 @@ This Web Part illustrates the following concepts on top of the SharePoint Framew
> Note that better pictures and documentation will increase the sample usage and the value you are providing for others. Thanks for your submissions in advance! You rock ❤.
> DELETE THIS PARAGRAPH BEFORE SUBMITTING
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/readme-template" />
## 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.**
## Support
We do not support samples, but we do use GitHub to track issues and constantly want to improve these samples.
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=YOUR-SOLUTION-NAME&authors=@YOURGITHUBUSERNAME&title=YOUR-SOLUTION-NAME%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=YOUR-SOLUTION-NAME&authors=@YOURGITHUBUSERNAME&title=YOUR-SOLUTION-NAME%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=YOUR-SOLUTION-NAME&authors=@YOURGITHUBUSERNAME&title=YOUR-SOLUTION-NAME%20-%20).
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/YOUR-SOLUTION-NAME" />

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": true,
"environment": "spo",
"version": "1.11.0",
"libraryName": "sp-fx-remote-event-receiver-manager",
"libraryId": "ad113c85-22f8-4414-aa78-4cb897d8a285",
"packageManager": "npm",
"isDomainIsolated": false,
"componentType": "webpart"
}
}

View File

@ -0,0 +1,66 @@
# Remote Event Receiver Manager
## Summary
A very simple web part that lets you add and delete remote event receivers to lists, the need came about due to remote event receivers not functioning properly when added with app only authentication and PnP.Powershell now only using that.
![Remote event receiver manager web part](./assets/video.gif)
## Compatibility
![SPFx 1.11](https://img.shields.io/badge/SPFx-1.11.0-green.svg)
![Node.js LTS 10.x](https://img.shields.io/badge/Node.js-LTS%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)
* [Office 365 tenant](https://docs.microsoft.com/sharepoint/dev/spfx/set-up-your-development-environment)
## Prerequisites
None
## Solution
Solution|Author(s)
--------|---------
react remote event receiver manager | [Dan Toft](https://github.com/Tanddant) ([@tanddant](https://twitter.com/tanddant))
## Version history
Version|Date|Comments
-------|----|--------
1.0.0|May 3, 2021|Initial release
## Minimal Path to Awesome - please follow all the steps.
- Clone this repository
- in the command line run:
- `npm install`
- `gulp build`
- `gulp bundle --ship`
- `gulp package-solution --ship`
- Add and deploy package to AppCatalog
## Features
- See, add, and delete remote event receivers from a list
## 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.**
## Support
We do not support samples, but we do use GitHub to track issues and constantly want to improve these samples.
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-remote-event-receiver-manager&authors=@Tanddant&title=react-remote-event-receiver-manager%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-remote-event-receiver-manager&authors=@Tanddant&title=react-remote-event-receiver-manager%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-remote-event-receiver-manager&authors=@Tanddant&title=react-remote-event-receiver-manager%20-%20).
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-remote-event-receiver-manager" />

View File

@ -0,0 +1,51 @@
[
{
"name": "pnp-sp-dev-spfx-web-parts-react-remote-event-receiver-manager",
"source": "pnp",
"title": "Remote Event Receiver Manager",
"shortDescription": "Lets you add and delete remote event receivers to lists",
"url": "https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-remote-event-receiver-manager",
"longDescription": [
"A very simple web part that lets you add and delete remote event receivers to lists, the need came about due to remote event receivers not functioning properly when added with app only authentication and PnP.Powershell now only using that."
],
"creationDateTime": "2021-05-03",
"updateDateTime": "2021-05-03",
"products": [
"SharePoint",
"Office"
],
"metadata": [
{
"key": "CLIENT-SIDE-DEV",
"value": "React"
},
{
"key": "SPFX-VERSION",
"value": "1.11.0"
}
],
"thumbnails": [
{
"type": "image",
"order": 100,
"url": "https://github.com/pnp/sp-dev-fx-webparts/raw/main/samples/react-remote-event-receiver-manager/assets/video.gif",
"alt": "Word Game"
}
],
"authors": [
{
"gitHubAccount": "Tanddant",
"company": "",
"pictureUrl": "https://github.com/Tanddant.png",
"name": "Dan Toft"
}
],
"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"
}
]
}
]

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 KiB

View File

@ -0,0 +1,18 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"remote-event-receiver-manager-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/remoteEventReceiverManager/RemoteEventReceiverManagerWebPart.js",
"manifest": "./src/webparts/remoteEventReceiverManager/RemoteEventReceiverManagerWebPart.manifest.json"
}
]
}
},
"externals": {},
"localizedResources": {
"RemoteEventReceiverManagerWebPartStrings": "lib/webparts/remoteEventReceiverManager/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": "sp-fx-remote-event-receiver-manager",
"accessKey": "<!-- ACCESS KEY -->"
}

View File

@ -0,0 +1,21 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "sp-fx-remote-event-receiver-manager-client-side-solution",
"id": "ad113c85-22f8-4414-aa78-4cb897d8a285",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"skipFeatureDeployment": true,
"isDomainIsolated": false,
"developer": {
"name": "",
"websiteUrl": "",
"privacyUrl": "",
"termsOfUseUrl": "",
"mpnId": ""
}
},
"paths": {
"zippedPackage": "solution/sp-fx-remote-event-receiver-manager.sppkg"
}
}

View File

@ -0,0 +1,10 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
"port": 4321,
"https": true,
"initialPage": "https://localhost:5432/workbench",
"api": {
"port": 5432,
"entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/"
}
}

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,41 @@
{
"name": "sp-fx-remote-event-receiver-manager",
"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/sp-core-library": "1.11.0",
"@microsoft/sp-lodash-subset": "1.11.0",
"@microsoft/sp-office-ui-fabric-core": "1.11.0",
"@microsoft/sp-property-pane": "1.11.0",
"@microsoft/sp-webpart-base": "1.11.0",
"@pnp/graph": "^2.4.0",
"@pnp/sp": "^2.4.0",
"office-ui-fabric-react": "6.214.0",
"react": "16.8.5",
"react-dom": "16.8.5"
},
"devDependencies": {
"@types/react": "16.8.8",
"@types/react-dom": "16.8.3",
"@microsoft/sp-build-web": "1.11.0",
"@microsoft/sp-tslint-rules": "1.11.0",
"@microsoft/sp-module-interfaces": "1.11.0",
"@microsoft/sp-webpart-workbench": "1.11.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",
"@types/webpack-env": "1.13.1",
"@types/es6-promise": "0.0.33"
}
}

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,27 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "b9b2c750-32a9-4db7-817f-fd0b23d73777",
"alias": "RemoteEventReceiverManagerWebPart",
"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": "Remote Event Receiver Manager" },
"description": { "default": "A simple webpart that lets you manage remote event receivers on the current site" },
"officeFabricIconFontName": "Remote",
"properties": {
"description": "Remote Event Receiver Manager"
}
}]
}

View File

@ -0,0 +1,60 @@
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version } from '@microsoft/sp-core-library';
import {
IPropertyPaneConfiguration
} from '@microsoft/sp-property-pane';
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
import * as strings from 'RemoteEventReceiverManagerWebPartStrings';
import RemoteEventReceiverManager from './components/RemoteEventReceiverManager';
import { IRemoteEventReceiverManagerProps } from './components/RemoteEventReceiverManager';
import { setup as pnpSetup } from "@pnp/common";
export interface IRemoteEventReceiverManagerWebPartProps {
}
export default class RemoteEventReceiverManagerWebPart extends BaseClientSideWebPart<IRemoteEventReceiverManagerWebPartProps> {
public render(): void {
const element: React.ReactElement<IRemoteEventReceiverManagerProps> = React.createElement(
RemoteEventReceiverManager,
{ context: this.context }
);
ReactDom.render(element, this.domElement);
}
protected onInit(): Promise<void> {
return super.onInit().then(_ => {
// other init code may be present
pnpSetup({
spfxContext: this.context
});
});
}
protected onDispose(): void {
ReactDom.unmountComponentAtNode(this.domElement);
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: ""
},
groups: []
}
]
};
}
}

View File

@ -0,0 +1,74 @@
@import '~office-ui-fabric-react/dist/sass/References.scss';
.remoteEventReceiverManager {
.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,205 @@
import * as React from 'react';
import styles from './RemoteEventReceiverManager.module.scss';
import { cloneDeep, escape } from '@microsoft/sp-lodash-subset';
import { IEventReceiver } from '../models/IEventReceiver';
import { IList } from '../models/IList';
import { ISharePointProvider, SharePointProvider } from '../providers/SharePointProvider';
import { ActionButton, DialogFooter, Dropdown, IDropdownOption, PrimaryButton, Spinner, SpinnerSize, Stack, Text, TextField } from 'office-ui-fabric-react';
import { WebPartContext } from '@microsoft/sp-webpart-base';
const SynchronizationOptions: IDropdownOption[] = [
{ key: 0, text: "DefaultSynchronization" },
{ key: 1, text: "Synchronous" },
{ key: 2, text: "Asynchronous" }
];
const EventTypeOptions: IDropdownOption[] = [
{ key: 10001, text: "ItemAdded" },
{ key: 10002, text: "ItemUpdated" },
{ key: 10003, text: "ItemDeleted" },
{ key: 10004, text: "ItemCheckedIn" },
{ key: 10005, text: "ItemCheckedOut" },
{ key: 10006, text: "ItemUncheckedOut" },
{ key: 10007, text: "ItemAttachmentAdded" },
{ key: 10008, text: "ItemAttachmentDeleted" },
{ key: 10009, text: "ItemFileMoved" },
{ key: 10010, text: "ItemFileConverted" },
{ key: 10011, text: "ItemVersionDeleted" },
];
const NewEventReciever: IEventReceiver = {
ReceiverAssembly: "Microsoft.SharePoint, Version=16.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c",
ReceiverClass: "Microsoft.SharePoint.Webhooks.SPWebhookItemEventReceiver",
ReceiverId: "",
ReceiverName: "",
SequenceNumber: 10000,
Synchronization: 2,
EventType: 10001,
ReceiverUrl: ""
};
export interface IRemoteEventReceiverManagerProps {
context: WebPartContext;
}
export interface IRemoteEventReceiverManagerState {
step: Step;
lists: IList[];
selectedList: IList;
eventReceivers: IEventReceiver[];
selectedEventReceiver: IEventReceiver;
isSaving: boolean;
}
export enum Step {
SelectList,
SelectEventReceiver,
EditEventReceiver
}
export default class RemoteEventReceiverManager extends React.Component<IRemoteEventReceiverManagerProps, IRemoteEventReceiverManagerState> {
private provider: ISharePointProvider;
constructor(props) {
super(props);
this.state = {
lists: null,
selectedList: null,
eventReceivers: null,
selectedEventReceiver: null,
step: Step.SelectList,
isSaving: false,
};
this.provider = new SharePointProvider(this.props.context);
this.loadInitialData();
}
private async loadInitialData() {
let lists = await this.provider.getLists();
this.setState({ lists: lists });
}
private async loadEventReceivers(Id: string) {
let EventReceivers = await this.provider.getEventReceivers(Id);
this.setState({ eventReceivers: EventReceivers });
}
private async addEventReceiver() {
this.setState({ isSaving: true });
await this.provider.addEventReceiver(this.state.selectedEventReceiver, this.state.selectedList.Id);
this.setState({ isSaving: false, selectedEventReceiver: null, step: Step.SelectEventReceiver });
this.loadEventReceivers(this.state.selectedList.Id);
}
private async deleteEventReceiver() {
this.setState({ isSaving: true });
await this.provider.deleteEventReceiver(this.state.selectedEventReceiver, this.state.selectedList.Id);
this.setState({ isSaving: false, selectedEventReceiver: null, step: Step.SelectEventReceiver });
this.loadEventReceivers(this.state.selectedList.Id);
}
public render(): React.ReactElement<IRemoteEventReceiverManagerProps> {
const { selectedEventReceiver } = this.state;
return (
<div className={styles.remoteEventReceiverManager}>
<div className={styles.container}>
<div className={styles.row}>
<div className={styles.column}>
{this.state.step == Step.SelectList &&
<div>
<Text variant={"large"}>Please select a list</Text>
{this.state.lists == null &&
<Spinner label={"Loading lists..."} size={SpinnerSize.large} />
}
{this.state.lists &&
<Stack tokens={{ childrenGap: 5 }} styles={{ root: { background: "white" } }}>
{this.state.lists.map((list, index) => {
return <ActionButton iconProps={{ iconName: "CustomList" }} text={list.Title} onClick={() => {
this.setState({ selectedList: { ...list }, step: Step.SelectEventReceiver });
this.loadEventReceivers(list.Id);
}} />;
})}
</Stack>
}
</div>
}
{this.state.step == Step.SelectEventReceiver &&
<div>
<ActionButton iconProps={{ iconName: "Back" }} text={"Go back"} styles={{ textContainer: { color: "white" } }} onClick={() => this.setState({ eventReceivers: null, step: Step.SelectList, selectedList: null })} />
<br />
<Text variant={"large"}>Please select a event receiver</Text>
<br />
{this.state.eventReceivers == null &&
<Spinner label={"Loading event receives..."} size={SpinnerSize.large} />
}
{this.state.eventReceivers &&
<div>
<Stack tokens={{ childrenGap: 5 }} styles={{ root: { background: "white" } }}>
{this.state.eventReceivers.map((eventReceiver, index) => {
return <ActionButton iconProps={{ iconName: "Remote" }} text={eventReceiver.ReceiverName} onClick={() => {
this.setState({ selectedEventReceiver: cloneDeep(eventReceiver), step: Step.EditEventReceiver });
}} />;
})}
</Stack>
<ActionButton iconProps={{ iconName: "Add" }} text={"Add new"} styles={{ textContainer: { color: "white" } }} onClick={() => this.setState({ selectedEventReceiver: cloneDeep(NewEventReciever), step: Step.EditEventReceiver })} />
</div>
}
</div>
}
{this.state.step == Step.EditEventReceiver &&
<div>
<ActionButton iconProps={{ iconName: "Back" }} text={"Go back"} styles={{ textContainer: { color: "white" } }} onClick={() => this.setState({ selectedEventReceiver: null, step: Step.SelectEventReceiver })} />
<br />
<TextField disabled={selectedEventReceiver.ReceiverId != ""} label={"ReceiverAssembly"} value={selectedEventReceiver.ReceiverAssembly} />
<TextField disabled={selectedEventReceiver.ReceiverId != ""} label={"ReceiverClass"} value={selectedEventReceiver.ReceiverClass} />
<TextField disabled label={"ReceiverId"} value={selectedEventReceiver.ReceiverId} />
<TextField disabled={selectedEventReceiver.ReceiverId != ""} label={"ReceiverName"} value={selectedEventReceiver.ReceiverName} onChange={(ev, val) => this.setState({ selectedEventReceiver: { ...selectedEventReceiver, ReceiverName: val } })} />
<TextField disabled={selectedEventReceiver.ReceiverId != ""} label={"SequenceNumber"} type={"number"} value={selectedEventReceiver.SequenceNumber + ""} onChange={(ev, val) => this.setState({ selectedEventReceiver: { ...selectedEventReceiver, SequenceNumber: val as any as number } })} />
<Dropdown disabled={selectedEventReceiver.ReceiverId != ""} label={"Synchronization"} selectedKey={selectedEventReceiver.Synchronization} onChange={(ev, val) => this.setState({ selectedEventReceiver: { ...selectedEventReceiver, Synchronization: val.key as number } })} options={SynchronizationOptions} />
<Dropdown disabled={selectedEventReceiver.ReceiverId != ""} label={"EventType"} selectedKey={selectedEventReceiver.EventType} onChange={(ev, val) => this.setState({ selectedEventReceiver: { ...selectedEventReceiver, EventType: val.key as number } })} options={EventTypeOptions} />
<TextField disabled={selectedEventReceiver.ReceiverId != ""} label={"ReceiverUrl"} value={selectedEventReceiver.ReceiverUrl} onChange={(ev, val) => this.setState({ selectedEventReceiver: { ...selectedEventReceiver, ReceiverUrl: val } })} />
<DialogFooter>
<div style={{ display: "flex", placeContent: "flex-end" }}>
{this.state.isSaving && <Spinner size={SpinnerSize.small} styles={{ root: { marginRight: 5 } }} />}
{selectedEventReceiver.ReceiverId == "" &&
<PrimaryButton text={"Save"} onClick={() => this.addEventReceiver()} />
}
{selectedEventReceiver.ReceiverId != "" &&
<PrimaryButton text={"Delete"} onClick={() => this.deleteEventReceiver()} styles={{ root: { background: "red" } }} />
}
</div>
</DialogFooter>
</div>
}
</div>
</div>
</div>
</div >
);
}
}

View File

@ -0,0 +1,7 @@
define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"DescriptionFieldLabel": "Description Field"
}
});

View File

@ -0,0 +1,10 @@
declare interface IRemoteEventReceiverManagerWebPartStrings {
PropertyPaneDescription: string;
BasicGroupName: string;
DescriptionFieldLabel: string;
}
declare module 'RemoteEventReceiverManagerWebPartStrings' {
const strings: IRemoteEventReceiverManagerWebPartStrings;
export = strings;
}

View File

@ -0,0 +1,11 @@
export interface IEventReceiver {
ReceiverAssembly: string;
ReceiverClass: string;
ReceiverId: string;
ReceiverName: string;
SequenceNumber: number;
Synchronization: number;
EventType: number;
ReceiverUrl: any;
}

View File

@ -0,0 +1,4 @@
export interface IList {
Title: string;
Id: string;
}

View File

@ -0,0 +1,70 @@
import { WebPartContext } from "@microsoft/sp-webpart-base";
import { sp } from "@pnp/sp/presets/all";
import { IEventReceiver } from "../models/IEventReceiver";
import { IList } from "../models/IList";
import { SPHttpClient, SPHttpClientConfiguration, SPHttpClientResponse, ODataVersion, ISPHttpClientConfiguration } from '@microsoft/sp-http';
export interface ISharePointProvider {
getLists(): Promise<IList[]>;
getEventReceivers(listID: string): Promise<IEventReceiver[]>;
addEventReceiver(eventReceiver: IEventReceiver, listId: string): Promise<void>;
deleteEventReceiver(eventReceiver: IEventReceiver, listId: string): Promise<void>;
}
export class SharePointProvider implements ISharePointProvider {
private context: WebPartContext;
constructor(context: WebPartContext) {
this.context = context;
}
public async getLists(): Promise<IList[]> {
try {
return await sp.web.lists.get();
} catch {
alert("Faild to get lists!");
}
}
public async getEventReceivers(listID: string): Promise<IEventReceiver[]> {
try {
let eventReceivers = await sp.web.lists.getById(listID).eventReceivers.get();
//Remove all OData properties as these will cause issues when saving later!
eventReceivers = eventReceivers.map(x => {
delete x["odata.editLink"];
delete x["odata.id"];
delete x["odata.type"];
return x;
});
return eventReceivers;
} catch {
alert("Failed to get event receivers!");
}
}
public async addEventReceiver(eventReceiver: IEventReceiver, listId: string): Promise<void> {
delete eventReceiver.ReceiverId;
let url = `${this.context.pageContext.web.absoluteUrl}/_api/web/lists(guid'${listId}')/EventReceivers`;
try {
let result = await this.context.spHttpClient.post(url, SPHttpClient.configurations.v1, { body: JSON.stringify(eventReceiver) });
} catch {
alert("Failed to add event receiver");
}
}
public async deleteEventReceiver(eventReceiver: IEventReceiver, listId: string): Promise<void> {
let header: HeadersInit = new Headers();
header.append("IF-MATCH", "*");
header.append("X-HTTP-Method", "DELETE");
let url = `${this.context.pageContext.web.absoluteUrl}/_api/web/lists(guid'${listId}')/EventReceivers/GetById(guid'${eventReceiver.ReceiverId}')`;
try {
let result = await this.context.spHttpClient.post(url, SPHttpClient.configurations.v1, { body: JSON.stringify(eventReceiver), headers: header });
} catch {
alert("Failed to delte event receiver");
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 383 B

View File

@ -0,0 +1,39 @@
{
"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",
"src/**/*.tsx"
],
"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
}
}