mirror of
https://github.com/pnp/sp-dev-fx-webparts.git
synced 2025-02-12 16:05:11 +00:00
Merge pull request #1178 from agtenr/dev
Thanks @agtenr this is a very timely sample and it looks great. Would you be interested in presenting this sample at an upcoming SPFx community call? We have an opening for April 9th if you're interested.
This commit is contained in:
commit
c0ad20c740
25
samples/react-covid19-info/.editorconfig
Normal file
25
samples/react-covid19-info/.editorconfig
Normal 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
|
32
samples/react-covid19-info/.gitignore
vendored
Normal file
32
samples/react-covid19-info/.gitignore
vendored
Normal 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
|
12
samples/react-covid19-info/.yo-rc.json
Normal file
12
samples/react-covid19-info/.yo-rc.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"isCreatingSolution": true,
|
||||
"environment": "spo",
|
||||
"version": "1.10.0",
|
||||
"libraryName": "spfx-covid-19-info",
|
||||
"libraryId": "8e6e959a-f902-4bb8-b1ff-ad7e45126607",
|
||||
"packageManager": "npm",
|
||||
"isDomainIsolated": false,
|
||||
"componentType": "webpart"
|
||||
}
|
||||
}
|
21
samples/react-covid19-info/LICENSE
Normal file
21
samples/react-covid19-info/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Robin Agten
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
77
samples/react-covid19-info/README.md
Normal file
77
samples/react-covid19-info/README.md
Normal file
@ -0,0 +1,77 @@
|
||||
# COVID 19 information web part
|
||||
|
||||
## Summary
|
||||
|
||||
This web part displays info about the COVID-19 virus for a given country.
|
||||
The following info is displayed:
|
||||
- Confirmed cases
|
||||
- Deaths
|
||||
- Recoverd
|
||||
|
||||
![COVID-19 info](./assets/covid-counter.gif)
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
|
||||
![drop](https://img.shields.io/badge/version-1.10.0-green.svg)
|
||||
|
||||
## Applies to
|
||||
|
||||
* [SharePoint Framework](https:/dev.office.com/sharepoint)
|
||||
* [Office 365 tenant](https://dev.office.com/sharepoint/docs/spfx/set-up-your-development-environment)
|
||||
|
||||
|
||||
## Solution
|
||||
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
react-covid19-info | [Robin Agten](https://twitter.com/AgtenRobin)
|
||||
|
||||
## Web part properties
|
||||
|
||||
| Property | Group | Description | Default |
|
||||
|-------------------------------------- |------------------------ |----------------------------------------------------------------------------------------------------------- |--------- |
|
||||
| iso2 Country Code | Country Settings | Defines the country for which the COVID-19 info should be displayed example: BE for Belgium | None |
|
||||
| Show history button | Web part configuration | Determines whether or not the history icon is shown. This can be used to show an graph of historical data | False |
|
||||
| View more statistics | Web part configuration | Provide an optional external link to more details statistics | None |
|
||||
| Up count duration | Web part configuration | Number of seconds for the counters to count up | 2 |
|
||||
| Color for the Confirmed Cases number | Web part configuration | Defines the color of the Confirmed cases number | #69797e |
|
||||
| Color for the Deaths number | Web part configuration | Defines the color of the Deaths number | #d13438 |
|
||||
| Color for the Recovered number | Web part configuration | Defines the color of the Recovered number | #498205 |
|
||||
|
||||
## Version history
|
||||
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0|March 25, 2020|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
|
||||
|
||||
* Clone this repository
|
||||
* in the command line run:
|
||||
* `npm install`
|
||||
* `gulp serve`
|
||||
|
||||
|
||||
## Features
|
||||
|
||||
* Configurable Country
|
||||
* Configurable Colors
|
||||
* Optional historical graph
|
||||
* Optional 'view more statistics' link
|
||||
|
||||
This Web Part illustrates the following concepts on top of the SharePoint Framework:
|
||||
|
||||
* Using external APIs using httpClient
|
||||
* [Office Fabric UI REact](https://developer.microsoft.com/en-us/fabric#/)
|
||||
* [SPFx Controls React](https://sharepoint.github.io/sp-dev-fx-controls-react/)
|
||||
* [SPFx Property Controls](https://sharepoint.github.io/sp-dev-fx-property-controls/)
|
||||
* [Recharts](http://recharts.org/en-US/)
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-covid19-info" />
|
||||
|
BIN
samples/react-covid19-info/assets/Langing-page-screenshot.png
Normal file
BIN
samples/react-covid19-info/assets/Langing-page-screenshot.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 846 KiB |
BIN
samples/react-covid19-info/assets/covid-counter.gif
Normal file
BIN
samples/react-covid19-info/assets/covid-counter.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.0 MiB |
19
samples/react-covid19-info/config/config.json
Normal file
19
samples/react-covid19-info/config/config.json
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
|
||||
"version": "2.0",
|
||||
"bundles": {
|
||||
"covid-19-info-web-part": {
|
||||
"components": [
|
||||
{
|
||||
"entrypoint": "./lib/webparts/covid19Info/Covid19InfoWebPart.js",
|
||||
"manifest": "./src/webparts/covid19Info/Covid19InfoWebPart.manifest.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"externals": {},
|
||||
"localizedResources": {
|
||||
"PropertyControlStrings": "node_modules/@pnp/spfx-property-controls/lib/loc/{locale}.js",
|
||||
"ControlStrings": "node_modules/@pnp/spfx-controls-react/lib/loc/{locale}.js"
|
||||
}
|
||||
}
|
4
samples/react-covid19-info/config/copy-assets.json
Normal file
4
samples/react-covid19-info/config/copy-assets.json
Normal file
@ -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": "spfx-covid-19-info",
|
||||
"accessKey": "<!-- ACCESS KEY -->"
|
||||
}
|
13
samples/react-covid19-info/config/package-solution.json
Normal file
13
samples/react-covid19-info/config/package-solution.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
|
||||
"solution": {
|
||||
"name": "spfx-covid-19-info-client-side-solution",
|
||||
"id": "8e6e959a-f902-4bb8-b1ff-ad7e45126607",
|
||||
"version": "1.0.0.0",
|
||||
"includeClientSideAssets": true,
|
||||
"isDomainIsolated": false
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/spfx-covid-19-info.sppkg"
|
||||
}
|
||||
}
|
10
samples/react-covid19-info/config/serve.json
Normal file
10
samples/react-covid19-info/config/serve.json
Normal 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/"
|
||||
}
|
||||
}
|
4
samples/react-covid19-info/config/write-manifests.json
Normal file
4
samples/react-covid19-info/config/write-manifests.json
Normal file
@ -0,0 +1,4 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/write-manifests.schema.json",
|
||||
"cdnBasePath": "<!-- PATH TO CDN -->"
|
||||
}
|
7
samples/react-covid19-info/gulpfile.js
vendored
Normal file
7
samples/react-covid19-info/gulpfile.js
vendored
Normal 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'));
|
18089
samples/react-covid19-info/package-lock.json
generated
Normal file
18089
samples/react-covid19-info/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
50
samples/react-covid19-info/package.json
Normal file
50
samples/react-covid19-info/package.json
Normal file
@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "spfx-covid-19-info",
|
||||
"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.10.0",
|
||||
"@microsoft/sp-lodash-subset": "1.10.0",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.10.0",
|
||||
"@microsoft/sp-property-pane": "1.10.0",
|
||||
"@microsoft/sp-webpart-base": "1.10.0",
|
||||
"@pnp/spfx-controls-react": "1.16.0",
|
||||
"@pnp/spfx-property-controls": "1.17.0",
|
||||
"@types/es6-promise": "0.0.33",
|
||||
"@types/react": "16.8.8",
|
||||
"@types/react-dom": "16.8.3",
|
||||
"@types/webpack-env": "1.13.1",
|
||||
"chart.js": "^2.9.3",
|
||||
"chartist": "^0.11.4",
|
||||
"office-ui-fabric-react": "6.189.2",
|
||||
"react": "16.8.5",
|
||||
"react-chartist": "^0.14.3",
|
||||
"react-chartkick": "^0.4.0",
|
||||
"react-countup": "^4.3.3",
|
||||
"react-dom": "16.8.5",
|
||||
"recharts": "^1.8.5"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "16.8.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/sp-build-web": "1.10.0",
|
||||
"@microsoft/sp-tslint-rules": "1.10.0",
|
||||
"@microsoft/sp-module-interfaces": "1.10.0",
|
||||
"@microsoft/sp-webpart-workbench": "1.10.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"
|
||||
}
|
||||
}
|
1
samples/react-covid19-info/src/index.ts
Normal file
1
samples/react-covid19-info/src/index.ts
Normal file
@ -0,0 +1 @@
|
||||
// A file is required to be in the root of the /src directory by the TypeScript compiler
|
17
samples/react-covid19-info/src/models/ICoronaInfo.ts
Normal file
17
samples/react-covid19-info/src/models/ICoronaInfo.ts
Normal file
@ -0,0 +1,17 @@
|
||||
export interface ICoronaInfo {
|
||||
countryregion: string;
|
||||
countrycode: ICountryCode;
|
||||
lastupdate: string;
|
||||
location: ILocation;
|
||||
confirmed: number;
|
||||
deaths: number;
|
||||
recovered: number;
|
||||
}
|
||||
export interface ILocation {
|
||||
lat: number;
|
||||
lng: number;
|
||||
}
|
||||
export interface ICountryCode {
|
||||
iso2: string;
|
||||
iso3: string;
|
||||
}
|
13
samples/react-covid19-info/src/models/ICoronaInfoHistory.ts
Normal file
13
samples/react-covid19-info/src/models/ICoronaInfoHistory.ts
Normal file
@ -0,0 +1,13 @@
|
||||
import { IDictionary } from "./IDictionary";
|
||||
|
||||
export interface ICoronaInfoHistory {
|
||||
countryregion: string;
|
||||
lastupdate: string;
|
||||
timeseries: IDictionary<TimeInfo>;
|
||||
}
|
||||
|
||||
export interface TimeInfo {
|
||||
confirmed: number;
|
||||
deaths: number;
|
||||
recovered: number;
|
||||
}
|
3
samples/react-covid19-info/src/models/IDictionary.ts
Normal file
3
samples/react-covid19-info/src/models/IDictionary.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export interface IDictionary<T> {
|
||||
[Key: string]: T;
|
||||
}
|
55
samples/react-covid19-info/src/services/CoronaService.ts
Normal file
55
samples/react-covid19-info/src/services/CoronaService.ts
Normal file
@ -0,0 +1,55 @@
|
||||
import { ICoronaService } from "./ICoronaService";
|
||||
import { HttpClient } from "@microsoft/sp-http";
|
||||
import { ICoronaInfo } from "../models/ICoronaInfo";
|
||||
import { ICoronaInfoHistory } from "../models/ICoronaInfoHistory";
|
||||
|
||||
export class CoronaService implements ICoronaService {
|
||||
|
||||
private httpClient: HttpClient;
|
||||
|
||||
constructor(httpClient: HttpClient) {
|
||||
this.httpClient = httpClient;
|
||||
}
|
||||
|
||||
public async getCountryInfo(countryCode: string): Promise<ICoronaInfo> {
|
||||
const response = await this.httpClient.get(
|
||||
`https://wuhan-coronavirus-api.laeyoung.endpoint.ainize.ai/jhu-edu/latest?iso2=${countryCode}&onlyCountries=true`,
|
||||
HttpClient.configurations.v1
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.text();
|
||||
console.log(error);
|
||||
throw Error(`Error while fetching the data for country with code '${countryCode}'`);
|
||||
}
|
||||
|
||||
const result: ICoronaInfo[] = await response.json();
|
||||
|
||||
if (result.length > 0) {
|
||||
return result[0];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public async getCountryHistory(countryCode: string): Promise<ICoronaInfoHistory> {
|
||||
const response = await this.httpClient.get(
|
||||
`https://wuhan-coronavirus-api.laeyoung.endpoint.ainize.ai/jhu-edu/timeseries?iso2=${countryCode}&onlyCountries=true`,
|
||||
HttpClient.configurations.v1
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.text();
|
||||
console.log(error);
|
||||
throw Error(`Error while fetching the data for country with code '${countryCode}'`);
|
||||
}
|
||||
|
||||
const result: ICoronaInfoHistory[] = await response.json();
|
||||
|
||||
if (result.length > 0) {
|
||||
return result[0];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
import { ICoronaInfo } from "../models/ICoronaInfo";
|
||||
import { ICoronaInfoHistory } from "../models/ICoronaInfoHistory";
|
||||
|
||||
export interface ICoronaService {
|
||||
getCountryInfo(countryCode: string): Promise<ICoronaInfo>;
|
||||
getCountryHistory(countryCode: string): Promise<ICoronaInfoHistory>;
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
|
||||
"id": "6f91d98b-45ec-4915-a409-0d789259c5c7",
|
||||
"alias": "Covid19InfoWebPart",
|
||||
"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": "COVID-19 Info" },
|
||||
"description": { "default": "Display regional COVID-19 information" },
|
||||
"officeFabricIconFontName": "Page",
|
||||
"properties": {
|
||||
"description": "COVID 19 Info"
|
||||
}
|
||||
}]
|
||||
}
|
@ -0,0 +1,137 @@
|
||||
import * as React from 'react';
|
||||
import * as ReactDom from 'react-dom';
|
||||
import { Version } from '@microsoft/sp-core-library';
|
||||
import {
|
||||
IPropertyPaneConfiguration,
|
||||
PropertyPaneTextField,
|
||||
PropertyPaneSlider,
|
||||
PropertyPaneToggle
|
||||
} from '@microsoft/sp-property-pane';
|
||||
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
|
||||
|
||||
import Covid19Info from './components/Covid19Info';
|
||||
import { ICovid19InfoProps } from './components/ICovid19InfoProps';
|
||||
import { PropertyFieldColorPicker, PropertyFieldColorPickerStyle } from '@pnp/spfx-property-controls/lib/PropertyFieldColorPicker';
|
||||
|
||||
|
||||
export interface ICovid19InfoWebPartProps {
|
||||
countryCode: string;
|
||||
showHistory: boolean;
|
||||
viewMoreLink: string;
|
||||
countUpTime: number;
|
||||
confirmedColor: string;
|
||||
deathColor: string;
|
||||
recoveredColor: string;
|
||||
}
|
||||
|
||||
export default class Covid19InfoWebPart extends BaseClientSideWebPart <ICovid19InfoWebPartProps> {
|
||||
|
||||
public render(): void {
|
||||
const element: React.ReactElement<ICovid19InfoProps> = React.createElement(
|
||||
Covid19Info,
|
||||
{
|
||||
countryCode: this.properties.countryCode,
|
||||
showHistory: this.properties.showHistory,
|
||||
viewMoreLink: this.properties.viewMoreLink,
|
||||
countUpTime: this.properties.countUpTime,
|
||||
confirmedColor: this.properties.confirmedColor,
|
||||
deathColor: this.properties.deathColor,
|
||||
recoveredColor: this.properties.recoveredColor,
|
||||
displayMode: this.displayMode,
|
||||
httpClient: this.context.httpClient,
|
||||
onConfigure: this._onConfigure
|
||||
}
|
||||
);
|
||||
|
||||
ReactDom.render(element, this.domElement);
|
||||
}
|
||||
|
||||
protected onDispose(): void {
|
||||
ReactDom.unmountComponentAtNode(this.domElement);
|
||||
}
|
||||
|
||||
protected get dataVersion(): Version {
|
||||
return Version.parse('1.0');
|
||||
}
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
header: {
|
||||
description: "Display regional COVID-19 information"
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
groupName: "Country Settings",
|
||||
groupFields: [
|
||||
PropertyPaneTextField('countryCode', {
|
||||
label: "iso2 Country Code (e.g. US)"
|
||||
})
|
||||
]
|
||||
},
|
||||
{
|
||||
groupName: "Web part configuration",
|
||||
groupFields: [
|
||||
PropertyPaneToggle('showHistory', {
|
||||
label: "Show 'View history' button"
|
||||
}),
|
||||
PropertyPaneTextField('viewMoreLink', {
|
||||
label: "Provide an optional link to view more statistics"
|
||||
}),
|
||||
PropertyPaneSlider('countUpTime', {
|
||||
label: "Number of second for the count up counters",
|
||||
min: 1,
|
||||
max: 20,
|
||||
value: 2,
|
||||
showValue: true,
|
||||
step:1
|
||||
}),
|
||||
PropertyFieldColorPicker('confirmedColor', {
|
||||
label: 'Color for the Confirmed Cases number',
|
||||
selectedColor: this.properties.confirmedColor,
|
||||
onPropertyChange: this.onPropertyPaneFieldChanged,
|
||||
properties: this.properties,
|
||||
disabled: false,
|
||||
isHidden: false,
|
||||
alphaSliderHidden: true,
|
||||
style: PropertyFieldColorPickerStyle.Inline,
|
||||
iconName: 'Precipitation',
|
||||
key: 'confirmedColorFieldId',
|
||||
}),
|
||||
PropertyFieldColorPicker('deathColor', {
|
||||
label: 'Color for the Deaths number',
|
||||
selectedColor: this.properties.deathColor,
|
||||
onPropertyChange: this.onPropertyPaneFieldChanged,
|
||||
properties: this.properties,
|
||||
disabled: false,
|
||||
isHidden: false,
|
||||
alphaSliderHidden: true,
|
||||
style: PropertyFieldColorPickerStyle.Inline,
|
||||
iconName: 'Precipitation',
|
||||
key: 'deathColorFieldId',
|
||||
}),
|
||||
PropertyFieldColorPicker('recoveredColor', {
|
||||
label: 'Color for the Recovered number',
|
||||
selectedColor: this.properties.recoveredColor,
|
||||
onPropertyChange: this.onPropertyPaneFieldChanged,
|
||||
properties: this.properties,
|
||||
disabled: false,
|
||||
isHidden: false,
|
||||
alphaSliderHidden: true,
|
||||
style: PropertyFieldColorPickerStyle.Inline,
|
||||
iconName: 'Precipitation',
|
||||
key: 'recoveredColorFieldId',
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
private _onConfigure = () => {
|
||||
this.context.propertyPane.open();
|
||||
}
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
@import '~office-ui-fabric-react/dist/sass/References.scss';
|
||||
|
||||
.covid19Info {
|
||||
.refreshIcon {
|
||||
position: absolute;
|
||||
right: 0px;
|
||||
z-index: 1;
|
||||
}
|
||||
.historyIcon{
|
||||
position: absolute;
|
||||
left: 0px;
|
||||
z-index: 1;
|
||||
}
|
||||
.container {
|
||||
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);
|
||||
|
||||
.countryRow{
|
||||
@include ms-Grid-row;
|
||||
.country {
|
||||
@include ms-Grid-col;
|
||||
@include ms-lg12;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
@include ms-font-xl;
|
||||
|
||||
.icon {
|
||||
margin-right: 15px;
|
||||
}
|
||||
.text {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.detailsRow{
|
||||
@include ms-Grid-row;
|
||||
padding: 10px;
|
||||
.infoColumn {
|
||||
@include ms-Grid-col;
|
||||
@include ms-md12;
|
||||
@include ms-lg4;
|
||||
text-align: center;
|
||||
.label {
|
||||
width: 100%;
|
||||
@include ms-font-l;
|
||||
}
|
||||
.number {
|
||||
padding: 15px;
|
||||
@include ms-font-xxl;
|
||||
}
|
||||
.confirmed {
|
||||
color: #69797e;
|
||||
}
|
||||
.deaths {
|
||||
color: #d13438;
|
||||
}
|
||||
|
||||
.recovered {
|
||||
color: #498205;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.lastUpdatedRow {
|
||||
@include ms-Grid-row;
|
||||
.lastUpdated {
|
||||
@include ms-Grid-col;
|
||||
@include ms-lg12;
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
@include ms-font-s;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -0,0 +1,249 @@
|
||||
import * as React from 'react';
|
||||
import styles from './Covid19Info.module.scss';
|
||||
import { ICovid19InfoProps } from './ICovid19InfoProps';
|
||||
import { ICovid19InfoState } from './ICovid19InfoState';
|
||||
import { DisplayMode } from '@microsoft/sp-core-library';
|
||||
import { Placeholder } from '@pnp/spfx-controls-react/lib/Placeholder';
|
||||
import { Spinner, SpinnerSize } from 'office-ui-fabric-react/lib/Spinner';
|
||||
import { MessageBar, MessageBarType } from 'office-ui-fabric-react/lib/MessageBar';
|
||||
import { Icon } from 'office-ui-fabric-react/lib/Icon';
|
||||
import { IconButton } from 'office-ui-fabric-react/lib/Button';
|
||||
import { Link } from 'office-ui-fabric-react/lib/Link';
|
||||
import { Modal, IModalStyleProps, IModalStyles } from 'office-ui-fabric-react/lib/Modal';
|
||||
import { mergeStyleSets, IStyle } from "office-ui-fabric-react/lib/Styling";
|
||||
import { ICoronaService } from '../../../services/ICoronaService';
|
||||
import { CoronaService } from '../../../services/CoronaService';
|
||||
import { HistoryModal } from "./HistoryModal/HistoryModal";
|
||||
import CountUp from "react-countup";
|
||||
import { ICoronaInfoHistory } from '../../../models/ICoronaInfoHistory';
|
||||
import { IStyleFunctionOrObject } from 'office-ui-fabric-react/lib/Utilities';
|
||||
|
||||
export default class Covid19Info extends React.Component<ICovid19InfoProps, ICovid19InfoState> {
|
||||
|
||||
private coronaService: ICoronaService;
|
||||
|
||||
constructor(props: ICovid19InfoProps) {
|
||||
super(props);
|
||||
|
||||
this.coronaService = new CoronaService(props.httpClient);
|
||||
|
||||
this.state = {
|
||||
isLoading: true,
|
||||
coronaInfo: undefined,
|
||||
globalError: undefined,
|
||||
showHistoryModal: false
|
||||
};
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
this._loadData();
|
||||
}
|
||||
|
||||
public componentDidUpdate(prevProps: ICovid19InfoProps) {
|
||||
if (prevProps.countryCode !== this.props.countryCode) {
|
||||
this._loadData();
|
||||
}
|
||||
}
|
||||
|
||||
public render(): React.ReactElement<ICovid19InfoProps> {
|
||||
|
||||
// No country code specified
|
||||
if (!this.props.countryCode) {
|
||||
if (this.props.displayMode === DisplayMode.Read) {
|
||||
return this._renderNoCountryCode();
|
||||
} else {
|
||||
return this._renderPlaceHolder();
|
||||
}
|
||||
}
|
||||
|
||||
// Is loading
|
||||
if (this.state.isLoading) {
|
||||
return this._renderSpinner();
|
||||
}
|
||||
|
||||
// Global Error
|
||||
if (this.state.globalError) {
|
||||
return this._renderError();
|
||||
}
|
||||
|
||||
// No data found
|
||||
if (this.state.coronaInfo === null) {
|
||||
return this._renderNoData();
|
||||
}
|
||||
const confirmedColor: string = this.props.confirmedColor
|
||||
? this.props.confirmedColor
|
||||
: "#69797e";
|
||||
|
||||
const deathColor: string = this.props.deathColor
|
||||
? this.props.deathColor
|
||||
: "#d13438";
|
||||
|
||||
const recoveredColor: string = this.props.recoveredColor
|
||||
? this.props.recoveredColor
|
||||
: "#498205";
|
||||
|
||||
return (
|
||||
<div className={styles.covid19Info}>
|
||||
<div className={styles.container}>
|
||||
{this.props.showHistory && (
|
||||
<IconButton
|
||||
className={styles.historyIcon}
|
||||
iconProps={{iconName: "Chart"}}
|
||||
label={"View history"}
|
||||
onClick={() => this._showHistoryModal()}
|
||||
/>
|
||||
)}
|
||||
<IconButton
|
||||
className={styles.refreshIcon}
|
||||
iconProps={{iconName: "Refresh"}}
|
||||
label={"Refresh data"}
|
||||
onClick={() => this._loadData()}
|
||||
/>
|
||||
<div className={styles.countryRow}>
|
||||
<div className={styles.country}>
|
||||
<Icon className={styles.icon} iconName={"Globe"}/>
|
||||
<span className={styles.text}>{this.state.coronaInfo.countryregion}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.detailsRow}>
|
||||
<div className={styles.infoColumn}>
|
||||
<div className={styles.label}>{"Confirmed Cases"}</div>
|
||||
<div className={styles.number} style={{ color: confirmedColor}}>
|
||||
<CountUp
|
||||
end={this.state.coronaInfo.confirmed}
|
||||
duration={this.props.countUpTime}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.infoColumn}>
|
||||
<div className={styles.label}>{"Deaths"}</div>
|
||||
<div className={styles.number} style={{ color: deathColor}}>
|
||||
<CountUp
|
||||
end={this.state.coronaInfo.deaths}
|
||||
duration={this.props.countUpTime}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.infoColumn}>
|
||||
<div className={styles.label}>{"Recovered"}</div>
|
||||
<div className={styles.number} style={{ color: recoveredColor}}>
|
||||
<CountUp
|
||||
end={this.state.coronaInfo.recovered}
|
||||
duration={this.props.countUpTime}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={styles.lastUpdatedRow}>
|
||||
<div className={styles.lastUpdated}>
|
||||
{`Last updated:
|
||||
${new Date(this.state.coronaInfo.lastupdate).toLocaleDateString()}
|
||||
${new Date(this.state.coronaInfo.lastupdate).toLocaleTimeString()}`
|
||||
}
|
||||
{this.props.viewMoreLink &&
|
||||
<span> - <Link target={"_blank"} href={this.props.viewMoreLink}>View more statistics</Link></span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
<Modal
|
||||
isOpen={this.state.showHistoryModal}
|
||||
onDismiss={this._closeHistoryModal}
|
||||
isBlocking={false}
|
||||
styles={this._getModalStyles()}
|
||||
>
|
||||
|
||||
<HistoryModal
|
||||
countryCode={this.props.countryCode}
|
||||
confirmedColor={confirmedColor}
|
||||
deathColor={deathColor}
|
||||
recoveredColor={recoveredColor}
|
||||
_loadHistoryData={this._loadHistoryData}
|
||||
/>
|
||||
</Modal>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private _loadData = async (): Promise<void> => {
|
||||
this.setState({isLoading: true});
|
||||
try {
|
||||
const coronaInfo = await this.coronaService.getCountryInfo(this.props.countryCode);
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
coronaInfo
|
||||
});
|
||||
} catch (error) {
|
||||
this.setState({
|
||||
coronaInfo: undefined,
|
||||
isLoading: false,
|
||||
globalError: (error as Error).message
|
||||
});
|
||||
}
|
||||
}
|
||||
private _loadHistoryData = async (): Promise<ICoronaInfoHistory> => {
|
||||
return await this.coronaService.getCountryHistory(this.props.countryCode);
|
||||
}
|
||||
private _showHistoryModal = (): void => {
|
||||
this.setState({
|
||||
showHistoryModal: true
|
||||
});
|
||||
}
|
||||
private _closeHistoryModal = (): void => {
|
||||
this.setState({
|
||||
showHistoryModal: false
|
||||
});
|
||||
}
|
||||
|
||||
private _renderNoCountryCode = (): JSX.Element => {
|
||||
return (
|
||||
<MessageBar messageBarType={MessageBarType.warning}>
|
||||
{"Please provide a country code in the web part properties!"}
|
||||
</MessageBar>
|
||||
);
|
||||
}
|
||||
private _renderPlaceHolder = (): JSX.Element => {
|
||||
return (
|
||||
<Placeholder
|
||||
iconName='Edit'
|
||||
iconText='Configure your web part'
|
||||
description='Please provide a country code in the web part properties'
|
||||
buttonLabel='Configure'
|
||||
onConfigure={this.props.onConfigure} />
|
||||
);
|
||||
}
|
||||
private _renderSpinner = () => {
|
||||
return (
|
||||
<Spinner
|
||||
label={"Loading COVID-19 data...."}
|
||||
size={SpinnerSize.medium}
|
||||
/>
|
||||
);
|
||||
}
|
||||
private _renderError = (): JSX.Element => {
|
||||
return (
|
||||
<MessageBar messageBarType={MessageBarType.error}>
|
||||
{this.state.globalError}
|
||||
</MessageBar>
|
||||
);
|
||||
}
|
||||
private _renderNoData = (): JSX.Element => {
|
||||
return (
|
||||
<MessageBar messageBarType={MessageBarType.info}>
|
||||
{`No COVID-19 data could be found for country code: '${this.props.countryCode}'`}
|
||||
</MessageBar>
|
||||
);
|
||||
}
|
||||
|
||||
private _getModalStyles = (): IStyleFunctionOrObject<IModalStyleProps, IModalStyles> => {
|
||||
const modalStyles: IStyleFunctionOrObject<IModalStyleProps, IModalStyles> = {
|
||||
main: {
|
||||
width: "750px",
|
||||
height: "500px",
|
||||
padding: "15px"
|
||||
}
|
||||
};
|
||||
|
||||
return modalStyles;
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
@import '~office-ui-fabric-react/dist/sass/References.scss';
|
||||
|
||||
.historyModalContainer {
|
||||
.countryRow{
|
||||
.country {
|
||||
padding: 10px;
|
||||
text-align: center;
|
||||
@include ms-font-xl;
|
||||
|
||||
.icon {
|
||||
margin-right: 15px;
|
||||
}
|
||||
.text {
|
||||
text-transform: uppercase;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.pivotChart{
|
||||
margin-top: 20px;
|
||||
}
|
||||
}
|
@ -0,0 +1,164 @@
|
||||
import * as React from 'react';
|
||||
import styles from './HistoryModal.module.scss';
|
||||
import { IHistoryModalProps } from "./IHistoryModalProps";
|
||||
import { IHistoryModalState } from "./IHistoryModalState";
|
||||
import { Spinner, SpinnerSize } from 'office-ui-fabric-react/lib/Spinner';
|
||||
import { MessageBar, MessageBarType } from 'office-ui-fabric-react/lib/MessageBar';
|
||||
import { ICoronaInfoHistory } from '../../../../models/ICoronaInfoHistory';
|
||||
import { LineChart, Line, XAxis, YAxis, CartesianGrid, Tooltip, Legend } from 'recharts';
|
||||
import { Pivot, PivotItem } from 'office-ui-fabric-react/lib/Pivot';
|
||||
import { IDataPoint } from "./IDataPoint";
|
||||
import { Icon } from 'office-ui-fabric-react/lib/Icon';
|
||||
|
||||
export class HistoryModal extends React.Component<IHistoryModalProps, IHistoryModalState> {
|
||||
|
||||
constructor(props: IHistoryModalProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
isLoading: true,
|
||||
globalError: undefined,
|
||||
historyData: undefined
|
||||
};
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
this._loadData();
|
||||
}
|
||||
|
||||
public render(): React.ReactElement<IHistoryModalProps> {
|
||||
|
||||
// Is loading
|
||||
if (this.state.isLoading) {
|
||||
return this._renderSpinner();
|
||||
}
|
||||
|
||||
// Global Error
|
||||
if (this.state.globalError) {
|
||||
return this._renderError();
|
||||
}
|
||||
|
||||
// No data found
|
||||
if (this.state.historyData === null) {
|
||||
return this._renderNoData();
|
||||
}
|
||||
|
||||
const mappedData = this._mapHistoryData(this.state.historyData);
|
||||
|
||||
return (
|
||||
<div className={styles.historyModalContainer}>
|
||||
<div className={styles.countryRow}>
|
||||
<div className={styles.country}>
|
||||
<Icon className={styles.icon} iconName={"Globe"}/>
|
||||
<span className={styles.text}>{this.state.historyData.countryregion}</span>
|
||||
</div>
|
||||
</div>
|
||||
<Pivot>
|
||||
<PivotItem className={styles.pivotChart} headerText={"Confirmed cases"}>
|
||||
{this._renderChart(mappedData, "confirmed", this.props.confirmedColor, false)}
|
||||
</PivotItem>
|
||||
<PivotItem headerText={"Deaths"}>
|
||||
{this._renderChart(mappedData, "deaths", this.props.deathColor, false)}
|
||||
</PivotItem>
|
||||
<PivotItem headerText={"Recovered"}>
|
||||
{this._renderChart(mappedData, "recovered", this.props.recoveredColor, false)}
|
||||
</PivotItem>
|
||||
<PivotItem headerText={"All"}>
|
||||
{this._renderChart(mappedData, null, null, true)}
|
||||
</PivotItem>
|
||||
</Pivot>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private _loadData = async (): Promise<void> => {
|
||||
this.setState({isLoading: true});
|
||||
try {
|
||||
const historyData: ICoronaInfoHistory = await this.props._loadHistoryData();
|
||||
this.setState({
|
||||
isLoading: false,
|
||||
historyData
|
||||
});
|
||||
} catch (error) {
|
||||
this.setState({
|
||||
historyData: undefined,
|
||||
isLoading: false,
|
||||
globalError: (error as Error).message
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private _mapHistoryData = (historyData: ICoronaInfoHistory): IDataPoint[] => {
|
||||
const dataPoints: IDataPoint[] = new Array();
|
||||
|
||||
for(let key in historyData.timeseries) {
|
||||
dataPoints.push({
|
||||
date: key,
|
||||
confirmed: historyData.timeseries[key].confirmed,
|
||||
deaths: historyData.timeseries[key].deaths,
|
||||
recovered: historyData.timeseries[key].recovered
|
||||
});
|
||||
}
|
||||
|
||||
return dataPoints;
|
||||
}
|
||||
|
||||
private _renderSpinner = () => {
|
||||
return (
|
||||
<Spinner
|
||||
label={"Loading COVID-19 data...."}
|
||||
size={SpinnerSize.medium}
|
||||
/>
|
||||
);
|
||||
}
|
||||
private _renderError = (): JSX.Element => {
|
||||
return (
|
||||
<MessageBar messageBarType={MessageBarType.error}>
|
||||
{this.state.globalError}
|
||||
</MessageBar>
|
||||
);
|
||||
}
|
||||
private _renderNoData = (): JSX.Element => {
|
||||
return (
|
||||
<MessageBar messageBarType={MessageBarType.info}>
|
||||
{`No historical data could be found for country code: '${this.props.countryCode}'`}
|
||||
</MessageBar>
|
||||
);
|
||||
}
|
||||
private _renderChart = (data: IDataPoint[], dataKey: string, color: string, showAll: boolean): JSX.Element => {
|
||||
if (showAll) {
|
||||
return (
|
||||
<LineChart
|
||||
width={700}
|
||||
height={300}
|
||||
data={data}
|
||||
margin={{
|
||||
top: 5, right: 30, left: 20, bottom: 5,
|
||||
}}
|
||||
>
|
||||
<CartesianGrid />
|
||||
<XAxis dataKey="date" />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
<Legend />
|
||||
<Line type={"monotone"} dataKey={"confirmed"} stroke={this.props.confirmedColor} />
|
||||
<Line type={"monotone"} dataKey={"deaths"} stroke={this.props.deathColor} />
|
||||
<Line type={"monotone"} dataKey={"recovered"} stroke={this.props.recoveredColor} />
|
||||
</LineChart>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<LineChart
|
||||
width={700}
|
||||
height={300}
|
||||
data={data}
|
||||
>
|
||||
<CartesianGrid />
|
||||
<XAxis dataKey="date" />
|
||||
<YAxis />
|
||||
<Tooltip />
|
||||
<Line type={"monotone"} dataKey={dataKey} stroke={color} />
|
||||
</LineChart>
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
export interface IDataPoint {
|
||||
date: string;
|
||||
confirmed: number;
|
||||
deaths: number;
|
||||
recovered: number;
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
import { ICoronaInfoHistory } from "../../../../models/ICoronaInfoHistory";
|
||||
|
||||
export interface IHistoryModalProps {
|
||||
countryCode: string;
|
||||
confirmedColor: string;
|
||||
deathColor: string;
|
||||
recoveredColor: string;
|
||||
_loadHistoryData(): Promise<ICoronaInfoHistory>;
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
import { ICoronaInfoHistory } from "../../../../models/ICoronaInfoHistory";
|
||||
|
||||
export interface IHistoryModalState {
|
||||
isLoading: boolean;
|
||||
historyData: ICoronaInfoHistory;
|
||||
globalError: string;
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
import { DisplayMode } from "@microsoft/sp-core-library";
|
||||
import { HttpClient } from "@microsoft/sp-http";
|
||||
|
||||
export interface ICovid19InfoProps {
|
||||
countryCode: string;
|
||||
showHistory: boolean;
|
||||
viewMoreLink: string;
|
||||
countUpTime: number;
|
||||
confirmedColor: string;
|
||||
deathColor: string;
|
||||
recoveredColor: string;
|
||||
displayMode: DisplayMode;
|
||||
httpClient: HttpClient;
|
||||
onConfigure(): void;
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
import { ICoronaInfo } from "../../../models/ICoronaInfo";
|
||||
|
||||
export interface ICovid19InfoState {
|
||||
isLoading: boolean;
|
||||
coronaInfo: ICoronaInfo;
|
||||
globalError: string;
|
||||
showHistoryModal: boolean;
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
38
samples/react-covid19-info/tsconfig.json
Normal file
38
samples/react-covid19-info/tsconfig.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"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"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"lib"
|
||||
]
|
||||
}
|
30
samples/react-covid19-info/tslint.json
Normal file
30
samples/react-covid19-info/tslint.json
Normal 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
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user