Merge pull request #2406 from anoopt/master
Updated react-graph-cascading-managed-metadata to SPFx v1.14
This commit is contained in:
commit
dbd6015364
|
@ -0,0 +1,39 @@
|
|||
// For more information on how to run this SPFx project in a VS Code Remote Container, please visit https://aka.ms/spfx-devcontainer
|
||||
{
|
||||
"name": "SPFx 1.14.0",
|
||||
"image": "docker.io/m365pnp/spfx:1.14.0",
|
||||
// Set *default* container specific settings.json values on container create.
|
||||
"settings": {},
|
||||
// Add the IDs of extensions you want installed when the container is created.
|
||||
"extensions": [
|
||||
"editorconfig.editorconfig",
|
||||
"dbaeumer.vscode-eslint"
|
||||
],
|
||||
// Use 'forwardPorts' to make a list of ports inside the container available locally.
|
||||
"forwardPorts": [
|
||||
4321,
|
||||
35729
|
||||
],
|
||||
"portsAttributes": {
|
||||
"4321": {
|
||||
"protocol": "https",
|
||||
"label": "Manifest",
|
||||
"onAutoForward": "silent",
|
||||
"requireLocalPort": true
|
||||
},
|
||||
// Not needed for SPFx>= 1.12.1
|
||||
// "5432": {
|
||||
// "protocol": "https",
|
||||
// "label": "Workbench",
|
||||
// "onAutoForward": "silent"
|
||||
// },
|
||||
"35729": {
|
||||
"protocol": "https",
|
||||
"label": "LiveReload",
|
||||
"onAutoForward": "silent",
|
||||
"requireLocalPort": true
|
||||
}
|
||||
},
|
||||
"postCreateCommand": "bash .devcontainer/spfx-startup.sh",
|
||||
"remoteUser": "node"
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
echo
|
||||
echo -e "\e[1;94mInstalling Node dependencies\e[0m"
|
||||
npm install
|
||||
|
||||
## commands to create dev certificate and copy it to the root folder of the project
|
||||
echo
|
||||
echo -e "\e[1;94mGenerating dev certificate\e[0m"
|
||||
gulp trust-dev-cert
|
||||
|
||||
# Convert the generated PEM certificate to a CER certificate
|
||||
openssl x509 -inform PEM -in ~/.rushstack/rushstack-serve.pem -outform DER -out ./spfx-dev-cert.cer
|
||||
|
||||
# Copy the PEM ecrtificate for non-Windows hosts
|
||||
cp ~/.rushstack/rushstack-serve.pem ./spfx-dev-cert.pem
|
||||
|
||||
## add *.cer to .gitignore to prevent certificates from being saved in repo
|
||||
if ! grep -Fxq '*.cer' ./.gitignore
|
||||
then
|
||||
echo "# .CER Certificates" >> .gitignore
|
||||
echo "*.cer" >> .gitignore
|
||||
fi
|
||||
|
||||
## add *.pem to .gitignore to prevent certificates from being saved in repo
|
||||
if ! grep -Fxq '*.pem' ./.gitignore
|
||||
then
|
||||
echo "# .PEM Certificates" >> .gitignore
|
||||
echo "*.pem" >> .gitignore
|
||||
fi
|
||||
|
||||
echo
|
||||
echo -e "\e[1;92mReady!\e[0m"
|
||||
|
||||
echo -e "\n\e[1;94m**********\nOptional: if you plan on using gulp serve, don't forget to add the container certificate to your local machine. Please visit https://aka.ms/spfx-devcontainer for more information\n**********"
|
|
@ -1,25 +0,0 @@
|
|||
# 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
|
|
@ -9,6 +9,7 @@ node_modules
|
|||
# Build generated files
|
||||
dist
|
||||
lib
|
||||
release
|
||||
solution
|
||||
temp
|
||||
*.sppkg
|
||||
|
@ -30,4 +31,7 @@ obj
|
|||
|
||||
# Styles Generated Code
|
||||
*.scss.ts
|
||||
*.scss.d.ts
|
||||
*.scss.d.ts# .CER Certificates
|
||||
*.cer
|
||||
# .PEM Certificates
|
||||
*.pem
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
!dist
|
||||
config
|
||||
|
||||
gulpfile.js
|
||||
|
||||
release
|
||||
src
|
||||
temp
|
||||
|
||||
tsconfig.json
|
||||
tslint.json
|
||||
|
||||
*.log
|
||||
|
||||
.yo-rc.json
|
||||
.vscode
|
|
@ -2,7 +2,7 @@
|
|||
"@microsoft/generator-sharepoint": {
|
||||
"isCreatingSolution": true,
|
||||
"environment": "spo",
|
||||
"version": "1.9.1",
|
||||
"version": "1.14.0",
|
||||
"libraryName": "react-graph-cascading-managed-metadata",
|
||||
"libraryId": "cdc626ca-e9a7-4d1d-bded-a574bc5e61d0",
|
||||
"packageManager": "npm",
|
||||
|
|
|
@ -8,19 +8,14 @@ This web part shows how to use the Microsoft Graph APIs (beta) for Taxonomy to g
|
|||
|
||||
![Cascading managed metadata](./assets/cmmd.gif)
|
||||
|
||||
### Termstore
|
||||
|
||||
![Term store](./assets/termstore.png)
|
||||
|
||||
## Compatibility
|
||||
|
||||
![SPFx 1.11](https://img.shields.io/badge/SPFx-1.11.0-green.svg)
|
||||
![Node.js v10](https://img.shields.io/badge/Node.js-v10-green.svg)
|
||||
![SPFx 1.14](https://img.shields.io/badge/SPFx-1.14-green.svg)
|
||||
![Node.js v14 | v12](https://img.shields.io/badge/Node.js-v14%20%7C%20v12-green.svg)
|
||||
![Compatible with SharePoint Online](https://img.shields.io/badge/SharePoint%20Online-Compatible-green.svg)
|
||||
![Does not work with SharePoint 2019](https://img.shields.io/badge/SharePoint%20Server%202019-Incompatible-red.svg "SharePoint Server 2019 requires SPFx 1.4.1 or lower")
|
||||
![Does not work with SharePoint 2016 (Feature Pack 2)](https://img.shields.io/badge/SharePoint%20Server%202016%20(Feature%20Pack%202)-Incompatible-red.svg "SharePoint Server 2016 Feature Pack 2 requires SPFx 1.1")
|
||||
![Teams Incompatible](https://img.shields.io/badge/Teams-Incompatible-lightgrey.svg)
|
||||
![Local Workbench Incompatible](https://img.shields.io/badge/Local%20Workbench-Incompatible-yellow.svg "This solution requires access to data terms using Microsoft Graph API")
|
||||
![Local Workbench Unsupported](https://img.shields.io/badge/Local%20Workbench-Unsupported-red.svg "Local workbench is no longer available as of SPFx 1.13 and above")
|
||||
![Hosted Workbench Compatible](https://img.shields.io/badge/Hosted%20Workbench-Compatible-green.svg)
|
||||
![Compatible with Remote Containers](https://img.shields.io/badge/Remote%20Containers-Compatible-green.svg)
|
||||
|
||||
|
@ -31,16 +26,18 @@ This web part shows how to use the Microsoft Graph APIs (beta) for Taxonomy to g
|
|||
|
||||
## Pre-requisites
|
||||
|
||||
* Set up the termset structure as shown in the image above.
|
||||
* Set up the termset structure as shown in the image below - .
|
||||
* To the termset, add a custom property called `UsedForShowingMaps` and set it's value to `true` as shown in the image below
|
||||
![Term store properties](./assets/termsetproperties.png)
|
||||
* For the cities, get the required latitude and longitude.
|
||||
* Set the description of the city term as `latitude;longitude` (as highlighted for the term `London` in the image above).
|
||||
|
||||
* Add 2 custom properties for the city terms `latitude` and `longitude` (as highlighted for the term `London` in the image below).
|
||||
![Term store](./assets/termstore.png)
|
||||
|
||||
## Solution
|
||||
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
react-graph-cascading-managed-metadata| Anoop Tatti ([anoopt](https://github.com/anoopt), [@anooptells](https://twitter.com/anooptells))
|
||||
react-graph-cascading-managed-metadata| Anoop Tatti ([anoopt](https://github.com/anoopt), ([https://linktr.ee/anoopt](https://linktr.ee/anoopt))
|
||||
|
||||
## Version history
|
||||
|
||||
|
@ -48,6 +45,7 @@ Version|Date|Comments
|
|||
-------|----|--------
|
||||
1.0.0|Aug 24, 2020|Initial release
|
||||
1.0.1|Sep 03, 2020|Error handling and logging improvements
|
||||
2.0.0|Mar 04, 2022|Updated to SPFx 1.14, used term `custom properties` to get co-ordinates (as Graph API provides that capability now), usage of `PropertyFieldGuid` and several other improvements
|
||||
|
||||
## Minimal Path to Awesome
|
||||
|
||||
|
@ -55,14 +53,17 @@ Version|Date|Comments
|
|||
* in the command line run:
|
||||
* `npm install`
|
||||
* `gulp serve`
|
||||
* Make sure you have completed the [pre-requisites](#Pre-requisites)
|
||||
* Add the web part to the workbench page of a site
|
||||
* Edit the web part and add the termset id in the properties
|
||||
|
||||
> This sample can also be opened with [VS Code Remote Development](https://code.visualstudio.com/docs/remote/remote-overview). Visit https://aka.ms/spfx-devcontainer for further instructions.
|
||||
> This sample can also be opened with [VS Code Remote Development](https://code.visualstudio.com/docs/remote/remote-overview). Visit <https://aka.ms/spfx-devcontainer> for further instructions.
|
||||
|
||||
## Features
|
||||
|
||||
This sample illustrates the following concepts on top of the SharePoint Framework:
|
||||
|
||||
* Get data terms using Microsoft Graph API (beta).
|
||||
* Get termset, terms and their custom properties using Microsoft Graph API (beta).
|
||||
* React Hooks
|
||||
* Using async / await for the async calls
|
||||
* Caching the data in session storage
|
||||
|
@ -72,12 +73,15 @@ This sample illustrates the following concepts on top of the SharePoint Framewor
|
|||
### Enhancements
|
||||
|
||||
* Currently, this web part supports 2-level cascading. So there is scope to enhance this such that it supports more levels of cascading dynamically.
|
||||
* Currently, this web part reads latitude and longitude from description of the city terms. If there is a way of getting these from the custom properties of the city terms, then that needs to be implemented.
|
||||
|
||||
## Video
|
||||
|
||||
[![Cascading managed metadata using Microsoft Graph and SharePoint Framework](./assets/video-thumbnail.jpg)](https://www.youtube.com/watch?v=lk47ijo_H6Y "Cascading managed metadata using Microsoft Graph and SharePoint Framework")
|
||||
|
||||
## Need to show more details?
|
||||
|
||||
An Adaptive Card Extension (ACE) which performs similar operations and provides more data like the local time of the office, weather data of the office location and address of the office location along with it's map can be found in the `Office locations` sample of [pnp/sp-dev-fx-aces repostory](https://github.com/pnp/sp-dev-fx-aces/tree/main/samples/ImageCard-OfficeLocations).
|
||||
|
||||
## Help
|
||||
|
||||
We do not support samples, but we this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues.
|
||||
|
@ -90,11 +94,8 @@ For questions regarding this sample, [create a new question](https://github.com/
|
|||
|
||||
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%3Aenhancement%2Csample%3A%20react-graph-cascading-managed-metadata&template=question.yml&sample=react-graph-cascading-managed-metadata&authors=@anoopt&title=react-graph-cascading-managed-metadata%20-%20).
|
||||
|
||||
|
||||
|
||||
## 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.**
|
||||
|
||||
|
||||
<img src="https://pnptelemetry.azurewebsites.net/sp-dev-fx-webparts/samples/react-graph-cascading-managed-metadata" />
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
"Shows how to use the Microsoft Graph APIs (beta) for Taxonomy to get the data."
|
||||
],
|
||||
"creationDateTime": "2020-09-02",
|
||||
"updateDateTime": "2020-09-02",
|
||||
"updateDateTime": "2022-03-02",
|
||||
"products": [
|
||||
"SharePoint"
|
||||
],
|
||||
|
@ -20,7 +20,7 @@
|
|||
},
|
||||
{
|
||||
"key": "SPFX-VERSION",
|
||||
"value": "1.11.0"
|
||||
"value": "1.14.0"
|
||||
}
|
||||
],
|
||||
"thumbnails": [
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 47 KiB |
Binary file not shown.
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 33 KiB |
|
@ -14,6 +14,7 @@
|
|||
"externals": {},
|
||||
"localizedResources": {
|
||||
"CascadingManagedMetadataWebPartStrings": "lib/webparts/cascadingManagedMetadata/loc/{locale}.js",
|
||||
"ControlStrings": "node_modules/@pnp/spfx-controls-react/lib/loc/{locale}.js"
|
||||
"ControlStrings": "node_modules/@pnp/spfx-controls-react/lib/loc/{locale}.js",
|
||||
"PropertyControlStrings": "node_modules/@pnp/spfx-property-controls/lib/loc/{locale}.js"
|
||||
}
|
||||
}
|
|
@ -1,4 +0,0 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json",
|
||||
"deployCdnPath": "temp/deploy"
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
|
||||
"workingDir": "./temp/deploy/",
|
||||
"workingDir": "./release/assets/",
|
||||
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
||||
"container": "react-graph-cascading-managed-metadata",
|
||||
"accessKey": "<!-- ACCESS KEY -->"
|
||||
|
|
|
@ -2,6 +2,21 @@
|
|||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
|
||||
"solution": {
|
||||
"name": "react-graph-cascading-managed-metadata-client-side-solution",
|
||||
"developer": {
|
||||
"name": "",
|
||||
"privacyUrl": "",
|
||||
"termsOfUseUrl": "",
|
||||
"websiteUrl": "",
|
||||
"mpnId": "Undefined-1.14.0"
|
||||
},
|
||||
"metadata": {
|
||||
"shortDescription": {
|
||||
"default": "react-graph-cascading-managed-metadata description"
|
||||
},
|
||||
"longDescription": {
|
||||
"default": "react-graph-cascading-managed-metadata description"
|
||||
}
|
||||
},
|
||||
"id": "cdc626ca-e9a7-4d1d-bded-a574bc5e61d0",
|
||||
"version": "1.0.0.0",
|
||||
"includeClientSideAssets": true,
|
||||
|
|
|
@ -2,9 +2,5 @@
|
|||
"$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/"
|
||||
}
|
||||
"initialPage": "https://enter-your-SharePoint-site/_layouts/workbench.aspx"
|
||||
}
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
{
|
||||
"$schema": "https://raw.githubusercontent.com/s-KaiNet/spfx-fast-serve/master/schema/config.latest.schema.json",
|
||||
"cli": {
|
||||
"isLibraryComponent": false
|
||||
},
|
||||
"serve": {
|
||||
"open": false
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* User webpack settings file. You can add your own settings here.
|
||||
* Changes from this file will be merged into the base webpack configuration file.
|
||||
* This file will not be overwritten by the subsequent spfx-fast-serve calls.
|
||||
*/
|
||||
|
||||
// you can add your project related webpack configuration here, it will be merged using webpack-merge module
|
||||
// i.e. plugins: [new webpack.Plugin()]
|
||||
const webpackConfig = {
|
||||
|
||||
}
|
||||
|
||||
// for even more fine-grained control, you can apply custom webpack settings using below function
|
||||
const transformConfig = function (initialWebpackConfig) {
|
||||
// transform the initial webpack config here, i.e.
|
||||
// initialWebpackConfig.plugins.push(new webpack.Plugin()); etc.
|
||||
|
||||
return initialWebpackConfig;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
webpackConfig,
|
||||
transformConfig
|
||||
}
|
|
@ -1,36 +1,21 @@
|
|||
'use strict';
|
||||
|
||||
const gulp = require('gulp');
|
||||
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.`);
|
||||
|
||||
const argv = build.rig.getYargs().argv;
|
||||
const useCustomServe = argv['custom-serve'];
|
||||
const fs = require("fs");
|
||||
const workbenchApi = require("@microsoft/sp-webpart-workbench/lib/api");
|
||||
var getTasks = build.rig.getTasks;
|
||||
build.rig.getTasks = function () {
|
||||
var result = getTasks.call(build.rig);
|
||||
|
||||
if (useCustomServe) {
|
||||
build.tslintCmd.enabled = false;
|
||||
result.set('serve', result.get('serve-deprecated'));
|
||||
|
||||
const ensureWorkbenchSubtask = build.subTask('ensure-workbench-task', function (gulp, buildOptions, done) {
|
||||
this.log('Creating workbench.html file...');
|
||||
try {
|
||||
workbenchApi.default["/workbench"]();
|
||||
} catch (e) { }
|
||||
return result;
|
||||
};
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
build.rig.addPostBuildTask(build.task('ensure-workbench', ensureWorkbenchSubtask));
|
||||
|
||||
build.configureWebpack.mergeConfig({
|
||||
additionalConfiguration: (generatedConfiguration) => {
|
||||
fs.writeFileSync("./temp/_webpack_config.json", JSON.stringify(generatedConfiguration, null, 2));
|
||||
return generatedConfiguration;
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
/* fast-serve */
|
||||
const { addFastServe } = require("spfx-fast-serve-helpers");
|
||||
addFastServe(build);
|
||||
/* end of fast-serve */
|
||||
|
||||
build.initialize(require('gulp'));
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,51 +3,34 @@
|
|||
"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",
|
||||
"serve": "cross-env NODE_OPTIONS=--max_old_space_size=4096 gulp bundle --custom-serve && cross-env NODE_OPTIONS=--max_old_space_size=4096 webpack-dev-server --mode development --config ./webpack.js --env.env=dev"
|
||||
"serve": "gulp bundle --custom-serve --max_old_space_size=4096 && fast-serve"
|
||||
},
|
||||
"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/spfx-controls-react": "^1.20.0-beta.52e4e9f",
|
||||
"office-ui-fabric-react": "6.214.0",
|
||||
"react": "16.8.5",
|
||||
"react-dom": "16.8.5"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "16.8.8"
|
||||
"@microsoft/sp-core-library": "1.14.0",
|
||||
"@microsoft/sp-lodash-subset": "1.14.0",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.14.0",
|
||||
"@microsoft/sp-property-pane": "1.14.0",
|
||||
"@microsoft/sp-webpart-base": "1.14.0",
|
||||
"@pnp/spfx-controls-react": "3.5.0",
|
||||
"@pnp/spfx-property-controls": "3.5.0",
|
||||
"office-ui-fabric-react": "7.174.1",
|
||||
"react": "16.13.1",
|
||||
"react-dom": "16.13.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/rush-stack-compiler-2.9": "0.7.16",
|
||||
"@microsoft/rush-stack-compiler-3.3": "0.3.5",
|
||||
"@microsoft/sp-build-web": "1.11.0",
|
||||
"@microsoft/sp-module-interfaces": "1.11.0",
|
||||
"@microsoft/sp-tslint-rules": "1.11.0",
|
||||
"@microsoft/sp-webpart-workbench": "1.11.0",
|
||||
"@types/chai": "3.4.34",
|
||||
"@types/mocha": "2.2.38",
|
||||
"@microsoft/rush-stack-compiler-3.9": "0.4.47",
|
||||
"@microsoft/sp-build-web": "1.14.0",
|
||||
"@microsoft/sp-module-interfaces": "1.14.0",
|
||||
"@microsoft/sp-tslint-rules": "1.14.0",
|
||||
"@types/react": "16.9.51",
|
||||
"@types/react-dom": "16.9.8",
|
||||
"@types/webpack-env": "1.13.1",
|
||||
"ajv": "~5.2.2",
|
||||
"cross-env": "7.0.2",
|
||||
"css-loader": "3.4.2",
|
||||
"css-modules-typescript-loader": "4.0.0",
|
||||
"del": "5.1.0",
|
||||
"fork-ts-checker-webpack-plugin": "4.1.0",
|
||||
"gulp": "~3.9.1",
|
||||
"node-sass": "4.13.1",
|
||||
"sass-loader": "8.0.2",
|
||||
"style-loader": "1.1.3",
|
||||
"ts-loader": "6.2.1",
|
||||
"webpack": "4.42.0",
|
||||
"webpack-cli": "3.3.11",
|
||||
"webpack-dev-server": "3.10.3"
|
||||
"gulp": "~4.0.2",
|
||||
"spfx-fast-serve-helpers": "~1.14.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
import * as React from 'react';
|
||||
import * as ReactDom from 'react-dom';
|
||||
import { Version, DisplayMode, Guid } from '@microsoft/sp-core-library';
|
||||
import {
|
||||
BaseClientSideWebPart,
|
||||
IPropertyPaneConfiguration,
|
||||
PropertyPaneTextField
|
||||
} from '@microsoft/sp-webpart-base';
|
||||
|
||||
import { Version, DisplayMode } from '@microsoft/sp-core-library';
|
||||
import { BaseClientSideWebPart } from "@microsoft/sp-webpart-base";
|
||||
import { IPropertyPaneConfiguration } from "@microsoft/sp-property-pane";
|
||||
import { PropertyFieldGuid } from '@pnp/spfx-property-controls/lib/PropertyFieldGuid';
|
||||
import * as strings from 'CascadingManagedMetadataWebPartStrings';
|
||||
import CascadingManagedMetadata from './components/CascadingManagedMetadata';
|
||||
import { MSGraph } from './services/MSGraph';
|
||||
|
@ -19,8 +16,12 @@ export default class CascadingManagedMetadataWebPart extends BaseClientSideWebPa
|
|||
|
||||
private _placeholder = null;
|
||||
|
||||
public async render(): Promise<void> {
|
||||
protected async onInit(): Promise<void> {
|
||||
await MSGraph.Init(this.context);
|
||||
return super.onInit();
|
||||
}
|
||||
|
||||
public async render(): Promise<void> {
|
||||
let renderElement = null;
|
||||
if (this.properties.termSetId) {
|
||||
renderElement = React.createElement(
|
||||
|
@ -68,18 +69,6 @@ export default class CascadingManagedMetadataWebPart extends BaseClientSideWebPa
|
|||
return Version.parse('1.0');
|
||||
}
|
||||
|
||||
private validateTermSetId(value: string): string {
|
||||
if (value === null ||
|
||||
value.trim().length === 0) {
|
||||
return 'Provide a term set Id.';
|
||||
}
|
||||
|
||||
if (!Guid.isValid(value.trim())) {
|
||||
return 'Term set Id must be a valid GUID.';
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
return {
|
||||
|
@ -92,9 +81,11 @@ export default class CascadingManagedMetadataWebPart extends BaseClientSideWebPa
|
|||
{
|
||||
groupName: strings.BasicGroupName,
|
||||
groupFields: [
|
||||
PropertyPaneTextField('termSetId', {
|
||||
PropertyFieldGuid('termSetId', {
|
||||
key: 'termSetId',
|
||||
label: strings.TermSetIdFieldLabel,
|
||||
onGetErrorMessage: this.validateTermSetId.bind(this)
|
||||
value: this.properties.termSetId,
|
||||
errorMessage: "Term set Id must be a valid GUID"
|
||||
})
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
import * as React from 'react';
|
||||
import styles from './CascadingManagedMetadata.module.scss';
|
||||
import { ICascadingManagedMetadataProps } from './ICascadingManagedMetadataProps';
|
||||
import { MSGraph } from '../services/MSGraph';
|
||||
import { ITerms } from '../../interfaces';
|
||||
import { ICMMDDropdownOption, IProperty, ITerms } from '../../interfaces';
|
||||
|
||||
import { Dropdown, IDropdownOption } from 'office-ui-fabric-react/lib/Dropdown';
|
||||
import { MessageBar, MessageBarType } from 'office-ui-fabric-react/lib/MessageBar';
|
||||
import { Map, ICoordinates } from "@pnp/spfx-controls-react/lib/Map";
|
||||
import { MMDService } from '../services/MMDService';
|
||||
import { find, isEmpty } from '@microsoft/sp-lodash-subset';
|
||||
|
||||
|
||||
const CascadingManagedMetadata: React.SFC<ICascadingManagedMetadataProps> = (props) => {
|
||||
|
||||
const [countriesList, setCountriesList] = React.useState<IDropdownOption[]>([]);
|
||||
const [citiesList, setCitiesList] = React.useState<IDropdownOption[]>([]);
|
||||
const [selectedCityCoordinates, setSelectedCityCoordinates] = React.useState<string>(null);
|
||||
const [citiesList, setCitiesList] = React.useState<ICMMDDropdownOption[]>([]);
|
||||
const [selectedCityKey, setselectedCityKey] = React.useState<string>(null);
|
||||
const [selectedCity, setSelectedCity] = React.useState<string>(null);
|
||||
const [showMap, setShowMap] = React.useState<boolean>(false);
|
||||
const [coordinates, setCoordinates] = React.useState<ICoordinates>({ latitude: null, longitude: null });
|
||||
|
@ -26,22 +26,34 @@ const CascadingManagedMetadata: React.SFC<ICascadingManagedMetadataProps> = (pro
|
|||
|
||||
const LOG_SOURCE: string = "Cascading MMD -";
|
||||
|
||||
React.useEffect(() => {
|
||||
_getCountries().then(countries => {
|
||||
if (countries) {
|
||||
const options: IDropdownOption[] = countries.value.map(c => ({ key: c.id, text: c.labels[0].name }));
|
||||
setCountriesList(options);
|
||||
} else {
|
||||
setCountriesList([]);
|
||||
clearData();
|
||||
//* Check if the term set has a property called UsedForShowingMaps
|
||||
const _checkIfTermsetIsUsedForShowingMaps = async (): Promise<boolean> => {
|
||||
try {
|
||||
const termsetData = await MSGraph.Call('get', `/termStore/sets/${props.termSetId}`, "beta", {}, ["properties"]);
|
||||
const termsetProperties: IProperty[] = termsetData.properties;
|
||||
console.debug("%s Retrieved termset properties. %o", LOG_SOURCE, termsetProperties);
|
||||
|
||||
if (isEmpty(termsetProperties)) {
|
||||
return false;
|
||||
}
|
||||
return find(termsetProperties, (p: IProperty) => p.key === "UsedForShowingMaps")?.value === "true";
|
||||
|
||||
}
|
||||
catch (error) {
|
||||
console.error("%s Error retrieving termset properties. Details - %o", LOG_SOURCE, error);
|
||||
setMessageBarStatus({
|
||||
type: MessageBarType.error,
|
||||
message: <span>Error retrieving termset properties. Please contact admin.</span>,
|
||||
show: true
|
||||
});
|
||||
}, [props.termSetId]); //* Run this also when the property termSetId changes
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
//* Get the country terms i.e. level 1 children using Graph
|
||||
const _getCountries = async (): Promise<ITerms> => {
|
||||
try {
|
||||
let countries: ITerms = await MSGraph.Get(`/termStore/sets/${props.termSetId}/children`, "beta");
|
||||
let countries: ITerms = await MSGraph.Call('get', `/termStore/sets/${props.termSetId}/children`, "beta");
|
||||
setMessageBarStatus(state => ({ ...state, show: false }));
|
||||
console.debug("%s Retrieved countries. %o", LOG_SOURCE, countries);
|
||||
return countries;
|
||||
|
@ -58,24 +70,29 @@ const CascadingManagedMetadata: React.SFC<ICascadingManagedMetadataProps> = (pro
|
|||
};
|
||||
|
||||
//* Get the city terms under a country i.e. level 2 children using Graph
|
||||
const _onCountryChange = (event: React.FormEvent<HTMLDivElement>, item: IDropdownOption): void => {
|
||||
const _onCountryChange = async (event: React.FormEvent<HTMLDivElement>, item: IDropdownOption): Promise<void> => {
|
||||
|
||||
try {
|
||||
clearData();
|
||||
let countryTermId: string = item.key.toString();
|
||||
|
||||
MMDService.GetTermsAsDropdownOptions(`/termStore/sets/${props.termSetId}/terms/${countryTermId}/children`, countryTermId, true)
|
||||
.then(options => {
|
||||
setCitiesList(options);
|
||||
//setShowMap(false);
|
||||
console.debug("%s Retrieved cities. %o", LOG_SOURCE, options);
|
||||
let cities: ICMMDDropdownOption[] = await MMDService
|
||||
.GetTermsAsDropdownOptions(
|
||||
`/termStore/sets/${props.termSetId}/terms/${countryTermId}/children`,
|
||||
["id", "labels", "properties"],
|
||||
countryTermId,
|
||||
true);
|
||||
setCitiesList(cities);
|
||||
setMessageBarStatus({
|
||||
type: MessageBarType.warning,
|
||||
message: options.length > 0 ?
|
||||
message: cities.length > 0 ?
|
||||
<span>To see the map, please select a city. </span> :
|
||||
<span> No city terms in the selected country.</span>,
|
||||
show: true
|
||||
});
|
||||
})
|
||||
.catch(error => {
|
||||
console.debug("%s Retrieved cities. %o", LOG_SOURCE, cities);
|
||||
}
|
||||
catch (error) {
|
||||
console.error("%s Error retrieving cities. Details - %o", LOG_SOURCE, error);
|
||||
setMessageBarStatus({
|
||||
type: MessageBarType.error,
|
||||
|
@ -83,26 +100,22 @@ const CascadingManagedMetadata: React.SFC<ICascadingManagedMetadataProps> = (pro
|
|||
show: true
|
||||
});
|
||||
setCitiesList([]);
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
//* Extract co-ordinates from key of the dropdown option
|
||||
//* The key will contain the description of the term
|
||||
//* The description of the term will be of the format latitude;longitude
|
||||
const _onCityChange = (event: React.FormEvent<HTMLDivElement>, item: IDropdownOption): void => {
|
||||
setSelectedCity(item.text);
|
||||
setSelectedCityCoordinates(item.key.toString());
|
||||
const [lat, long] = item.key.toString().split(';');
|
||||
const coordinates: ICoordinates = {
|
||||
latitude: isNaN(Number(lat)) ? null : Number(lat),
|
||||
longitude: isNaN(Number(long)) ? null : Number(long)
|
||||
};
|
||||
setCoordinates(coordinates);
|
||||
|
||||
console.debug("%s Retrieved coordinates. %o", LOG_SOURCE, coordinates);
|
||||
const _onCityChange = (event: React.FormEvent<HTMLDivElement>, item: ICMMDDropdownOption): void => {
|
||||
|
||||
if (coordinates.latitude && coordinates.longitude) {
|
||||
const { text, key, data } = item;
|
||||
|
||||
setSelectedCity(text);
|
||||
setselectedCityKey(key.toString());
|
||||
setCoordinates(data);
|
||||
|
||||
console.debug("%s Retrieved coordinates. %o", LOG_SOURCE, data);
|
||||
|
||||
if (data.latitude && data.longitude) {
|
||||
setShowMap(true);
|
||||
setMessageBarStatus(state => ({ ...state, show: false }));
|
||||
} else {
|
||||
|
@ -118,12 +131,60 @@ const CascadingManagedMetadata: React.SFC<ICascadingManagedMetadataProps> = (pro
|
|||
//* Clear the data related to cities and maps
|
||||
const clearData = () => {
|
||||
setCoordinates({ latitude: null, longitude: null });
|
||||
setSelectedCityCoordinates(null);
|
||||
setselectedCityKey(null);
|
||||
setSelectedCity(null);
|
||||
setCitiesList([]);
|
||||
setShowMap(false);
|
||||
};
|
||||
|
||||
const _start = async (): Promise<void> => {
|
||||
|
||||
let isTermsetUsedForShowingMaps: boolean = await _checkIfTermsetIsUsedForShowingMaps();
|
||||
|
||||
if(isTermsetUsedForShowingMaps === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isTermsetUsedForShowingMaps) {
|
||||
setCountriesList([]);
|
||||
clearData();
|
||||
setMessageBarStatus({
|
||||
type: MessageBarType.warning,
|
||||
message: <span>The selected term set is not used for showing maps.</span>,
|
||||
show: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
let countries: ITerms = await _getCountries();
|
||||
|
||||
if(countries === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isEmpty(countries.value)) {
|
||||
setCountriesList([]);
|
||||
clearData();
|
||||
setMessageBarStatus({
|
||||
type: MessageBarType.warning,
|
||||
message: <span>No country terms in the selected termset. Please contact admin.</span>,
|
||||
show: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Renamed to avoid shadowed variables
|
||||
let localCountriesList: IDropdownOption[] = countries.value.map(c => ({ key: c.id, text: c.labels[0].name }));
|
||||
setCountriesList(localCountriesList);
|
||||
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
_start();
|
||||
}, [props.termSetId]); //* Run this also when the property termSetId changes
|
||||
|
||||
|
||||
|
||||
return (
|
||||
<div>
|
||||
<Dropdown
|
||||
|
@ -136,7 +197,7 @@ const CascadingManagedMetadata: React.SFC<ICascadingManagedMetadataProps> = (pro
|
|||
|
||||
<Dropdown
|
||||
label="City"
|
||||
selectedKey={selectedCityCoordinates}
|
||||
selectedKey={selectedCityKey}
|
||||
placeHolder="Select a city"
|
||||
options={citiesList}
|
||||
onChange={_onCityChange}
|
||||
|
|
|
@ -1,47 +1,44 @@
|
|||
import { ITerms, IOption } from "../../interfaces";
|
||||
import { ITerms, ICMMDDropdownOption } from "../../interfaces";
|
||||
import { MSGraph } from "./MSGraph";
|
||||
import { IDropdownOption } from "office-ui-fabric-react/lib/Dropdown";
|
||||
import { find } from '@microsoft/sp-lodash-subset';
|
||||
|
||||
export class MMDService {
|
||||
|
||||
private static _sessionStorageKey: string = "CMMD_Options";
|
||||
private static _logSource: string = "Cascading MMD Service -";
|
||||
|
||||
public static async GetTermsAsDropdownOptions(apiUrl: string, parent: string, tryFromCache: boolean): Promise<IDropdownOption[]> {
|
||||
|
||||
let options: IDropdownOption[] = [];
|
||||
public static async GetTermsAsDropdownOptions(apiUrl: string, selectProperties: string[], parent: string, tryFromCache: boolean): Promise<ICMMDDropdownOption[]> {
|
||||
if (tryFromCache) {
|
||||
let optionsFromCache: IOption[] = this._fetchFromSessionStorge();
|
||||
let optionsFromCache: ICMMDDropdownOption[] = this._fetchFromSessionStorge();
|
||||
|
||||
if (optionsFromCache.length) {
|
||||
let requiredOptionsFromCache = optionsFromCache.filter(o => o.parent == parent);
|
||||
if (requiredOptionsFromCache.length) {
|
||||
options = requiredOptionsFromCache.map(r => ({ key: r.key, text: r.text }));
|
||||
return options;
|
||||
return requiredOptionsFromCache;
|
||||
}
|
||||
}
|
||||
}
|
||||
//Get data using Graph
|
||||
return await this._getTermsAsDropdownOptionsUsingGraph(apiUrl, parent);
|
||||
return await this._getTermsAsDropdownOptionsUsingGraph(apiUrl, selectProperties, parent);
|
||||
}
|
||||
|
||||
private static async _getTermsAsDropdownOptionsUsingGraph(apiUrl: string, parent: string): Promise<IDropdownOption[]> {
|
||||
private static async _getTermsAsDropdownOptionsUsingGraph(apiUrl: string, selectProperties: string[], parent: string): Promise<ICMMDDropdownOption[]> {
|
||||
try {
|
||||
let terms: ITerms = await MSGraph.Get(apiUrl, "beta");
|
||||
let terms: ITerms = await MSGraph.Call("get", apiUrl, "beta", {}, selectProperties);
|
||||
if (terms.value) {
|
||||
//* Set key as description of the term
|
||||
//* Description will be of the format latitude;longitude
|
||||
//* This will be used to render maps
|
||||
const options: IDropdownOption[] = terms.value.map(t => ({
|
||||
key: t.descriptions[0] ? t.descriptions[0].description : t.id,
|
||||
text: t.labels[0].name
|
||||
}));
|
||||
let optionsToStoreInCache: IOption[] = options.map(o => ({
|
||||
key: o.key.toString(),
|
||||
text: o.text,
|
||||
const options: ICMMDDropdownOption[] = terms.value.map(t => ({
|
||||
key: t.id,
|
||||
text: t.labels[0].name,
|
||||
data: {
|
||||
latitude: Number(find(t.properties, p => p.key === "latitude")?.value) ?? null,
|
||||
longitude: Number(find(t.properties, p => p.key === "longitude")?.value) ?? null,
|
||||
},
|
||||
parent
|
||||
}));
|
||||
let optionsFromCache: IOption[] = this._fetchFromSessionStorge();
|
||||
optionsToStoreInCache = [...optionsFromCache, ...optionsToStoreInCache];
|
||||
|
||||
let optionsFromCache: ICMMDDropdownOption[] = this._fetchFromSessionStorge();
|
||||
let optionsToStoreInCache: ICMMDDropdownOption[] = [...optionsFromCache, ...options];
|
||||
window.sessionStorage.setItem(this._sessionStorageKey, JSON.stringify(optionsToStoreInCache));
|
||||
console.debug("%s Data added in cache.", this._logSource);
|
||||
return options;
|
||||
|
@ -55,8 +52,8 @@ export class MMDService {
|
|||
|
||||
}
|
||||
|
||||
private static _fetchFromSessionStorge(): IOption[] {
|
||||
let result: IOption[] = [];
|
||||
private static _fetchFromSessionStorge(): ICMMDDropdownOption[] {
|
||||
let result: ICMMDDropdownOption[] = [];
|
||||
let stringResult: string = window.sessionStorage.getItem(this._sessionStorageKey);
|
||||
if (stringResult) {
|
||||
try {
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
//* Helper wrapper for calling Graph
|
||||
//* based on https://gist.github.com/wobba/37416d3107b85675d896105554b3df28
|
||||
//* Thank you Mikael Svenson
|
||||
|
||||
import { WebPartContext } from '@microsoft/sp-webpart-base';
|
||||
|
@ -6,84 +8,37 @@ import { MSGraphClient } from '@microsoft/sp-http';
|
|||
|
||||
export class MSGraph {
|
||||
private static _graphClient: MSGraphClient;
|
||||
|
||||
public static async Init(context: WebPartContext) {
|
||||
this._graphClient = await context.msGraphClientFactory.getClient();
|
||||
}
|
||||
|
||||
public static async Get(apiUrl: string, version: string = "v1.0", selectProperties?: string[], expandProperties?: string[], filter?: string): Promise<any> {
|
||||
public static async Call(
|
||||
method: "get" | "post" | "patch" | "delete",
|
||||
apiUrl: string,
|
||||
version: "v1.0" | "beta",
|
||||
content?: any,
|
||||
selectProperties?: string[],
|
||||
expandProperties?: string[],
|
||||
filter?: string,
|
||||
count?: boolean
|
||||
): Promise<any> {
|
||||
|
||||
var p = new Promise<string>(async (resolve, reject) => {
|
||||
let query = this._graphClient.api(apiUrl).version(version);
|
||||
if (selectProperties && selectProperties.length > 0) {
|
||||
query = query.select(selectProperties);
|
||||
}
|
||||
if (filter && filter.length > 0) {
|
||||
query = query.filter(filter);
|
||||
}
|
||||
if (expandProperties && expandProperties.length > 0) {
|
||||
query = query.expand(expandProperties);
|
||||
}
|
||||
|
||||
let callback = (error: GraphError, response: any, rawResponse?: any) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(response);
|
||||
}
|
||||
};
|
||||
await query.get(callback);
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
public static async Patch(apiUrl: string, version: string = "v1.0", content: any): Promise<any> {
|
||||
var p = new Promise<string>(async (resolve, reject) => {
|
||||
if (typeof (content) === "object") {
|
||||
content = JSON.stringify(content);
|
||||
}
|
||||
|
||||
let query = this._graphClient.api(apiUrl).version(version);
|
||||
let callback = (error: GraphError, _response: any, rawResponse?: any) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
await query.update(content, callback);
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
public static async Post(apiUrl: string, version: string = "v1.0", content: any): Promise<any> {
|
||||
var p = new Promise<string>(async (resolve, reject) => {
|
||||
if (typeof (content) === "object") {
|
||||
content = JSON.stringify(content);
|
||||
}
|
||||
|
||||
let query = this._graphClient.api(apiUrl).version(version);
|
||||
let callback = (error: GraphError, response: any, rawResponse?: any) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(response);
|
||||
}
|
||||
};
|
||||
await query.post(content, callback);
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
||||
public static async Delete(apiUrl: string, version: string = "v1.0"): Promise<any> {
|
||||
var p = new Promise<string>(async (resolve, reject) => {
|
||||
let query = this._graphClient.api(apiUrl).version(version);
|
||||
let callback = (error: GraphError, response: any, rawResponse?: any) => {
|
||||
if (error) {
|
||||
reject(error);
|
||||
} else {
|
||||
resolve(response);
|
||||
}
|
||||
};
|
||||
await query.delete(callback);
|
||||
// tslint:disable-next-line: no-unused-expression
|
||||
typeof(content) === "object" && (content = JSON.stringify(content));
|
||||
// tslint:disable-next-line: no-unused-expression
|
||||
selectProperties && selectProperties.length > 0 && (query = query.select(selectProperties));
|
||||
// tslint:disable-next-line: no-unused-expression
|
||||
filter && filter.length > 0 && (query = query.filter(filter));
|
||||
// tslint:disable-next-line: no-unused-expression
|
||||
expandProperties && expandProperties.length > 0 && (query = query.expand(expandProperties));
|
||||
// tslint:disable-next-line: no-unused-expression
|
||||
count && (query = query.count(count));
|
||||
let callback = (error: GraphError, response: any, rawResponse?: any) => error ? reject(error) : resolve(response);
|
||||
//* ES2016
|
||||
["post", "patch"].includes(method) ? await query[method](content, callback) : await query[method](callback);
|
||||
});
|
||||
return p;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
import { IDropdownOption } from "office-ui-fabric-react/lib/Dropdown";
|
||||
import { ICoordinates } from "@pnp/spfx-controls-react/lib/Map";
|
||||
|
||||
export interface ICMMDDropdownOption extends IDropdownOption {
|
||||
data: ICoordinates;
|
||||
parent?: string;
|
||||
}
|
|
@ -1,5 +0,0 @@
|
|||
export interface IOption {
|
||||
key: string;
|
||||
text: string;
|
||||
parent: string;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
export interface IProperty {
|
||||
key: string;
|
||||
value: string;
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
import { IDescription } from "./IDescription";
|
||||
import { ILabel } from "./ILabel";
|
||||
import { IProperty, ILabel, IDescription } from ".";
|
||||
|
||||
export interface ITerm {
|
||||
id: string;
|
||||
|
@ -7,4 +6,5 @@ export interface ITerm {
|
|||
lastModifiedDateTime: Date;
|
||||
labels: ILabel[];
|
||||
descriptions: IDescription[];
|
||||
properties: IProperty[];
|
||||
}
|
|
@ -2,4 +2,5 @@ export { ILabel } from './ILabel';
|
|||
export { IDescription } from './IDescription';
|
||||
export { ITerm } from './ITerm';
|
||||
export { ITerms } from './ITerms';
|
||||
export { IOption } from './IOption';
|
||||
export { IProperty } from './IProperty';
|
||||
export { ICMMDDropdownOption } from './ICMMDDropdownOption';
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"extends": "./node_modules/@microsoft/rush-stack-compiler-2.9/includes/tsconfig-web.json",
|
||||
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.9/includes/tsconfig-web.json",
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
|
@ -19,20 +19,18 @@
|
|||
"./node_modules/@microsoft"
|
||||
],
|
||||
"types": [
|
||||
"es6-promise",
|
||||
"webpack-env"
|
||||
],
|
||||
"lib": [
|
||||
"es5",
|
||||
"dom",
|
||||
"es2015.collection"
|
||||
"es2015.collection",
|
||||
"es2015.promise",
|
||||
"ES2016.Array.Include"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"lib"
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"extends": "@microsoft/sp-tslint-rules/base-tslint.json",
|
||||
"extends": "./node_modules/@microsoft/sp-tslint-rules/base-tslint.json",
|
||||
"rules": {
|
||||
"class-name": false,
|
||||
"export-name": false,
|
||||
|
@ -17,7 +17,6 @@
|
|||
"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,
|
||||
|
|
Loading…
Reference in New Issue