Added react-remote-event-receiver-manager sample

This commit is contained in:
Tanddant 2021-05-03 21:03:42 +02:00
parent 57ec332b73
commit 049cc19ec3
28 changed files with 19556 additions and 0 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": 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,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

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,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: []
}
]
};
}
}

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
}
}