Added react-remote-event-receiver-manager sample
This commit is contained in:
parent
57ec332b73
commit
049cc19ec3
|
@ -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
|
|
@ -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
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
# Birthdays
|
||||
|
||||
## Summary
|
||||
A very simple webpart that let's 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 reciver manager webpart](./assets/video.gif)
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
![1.11.0](https://img.shields.io/badge/version-1.11.0-green.svg)
|
||||
|
||||
## 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
|
||||
|
||||
## Version history
|
||||
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0.0|May 3, 2021|Initial release
|
||||
|
||||
## 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.**
|
||||
|
||||
---
|
||||
|
||||
## 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 `
|
||||
- `Go to API Management - from SharePoint Admin Center new experience, and Approve the Permission Require to Use Graph API SCOPES`
|
||||
|
||||
|
||||
|
||||
## Features
|
||||
- See, add, and delete remote event receivers from a list
|
Binary file not shown.
After Width: | Height: | Size: 274 KiB |
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json",
|
||||
"deployCdnPath": "temp/deploy"
|
||||
}
|
|
@ -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 -->"
|
||||
}
|
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -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/"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/write-manifests.schema.json",
|
||||
"cdnBasePath": "<!-- PATH TO CDN -->"
|
||||
}
|
|
@ -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
|
@ -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"
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
// A file is required to be in the root of the /src directory by the TypeScript compiler
|
|
@ -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"
|
||||
}
|
||||
}]
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
import * as React from 'react';
|
||||
import * as ReactDom from 'react-dom';
|
||||
import { Version } from '@microsoft/sp-core-library';
|
||||
import {
|
||||
IPropertyPaneConfiguration,
|
||||
PropertyPaneTextField
|
||||
} 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: []
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 >
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
define([], function() {
|
||||
return {
|
||||
"PropertyPaneDescription": "Description",
|
||||
"BasicGroupName": "Group Name",
|
||||
"DescriptionFieldLabel": "Description Field"
|
||||
}
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
declare interface IRemoteEventReceiverManagerWebPartStrings {
|
||||
PropertyPaneDescription: string;
|
||||
BasicGroupName: string;
|
||||
DescriptionFieldLabel: string;
|
||||
}
|
||||
|
||||
declare module 'RemoteEventReceiverManagerWebPartStrings' {
|
||||
const strings: IRemoteEventReceiverManagerWebPartStrings;
|
||||
export = strings;
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
export interface IEventReceiver {
|
||||
ReceiverAssembly: string;
|
||||
ReceiverClass: string;
|
||||
ReceiverId: string;
|
||||
ReceiverName: string;
|
||||
SequenceNumber: number;
|
||||
Synchronization: number;
|
||||
EventType: number;
|
||||
ReceiverUrl: any;
|
||||
}
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
export interface IList {
|
||||
Title: string;
|
||||
Id: string;
|
||||
}
|
|
@ -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 |
|
@ -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"
|
||||
]
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue