React project online (#349)

* Add new web part

* Add project

* Update README.md

* Add assets

* Update README.md

* Update README.md
This commit is contained in:
Joel Rodrigues 2017-11-06 07:28:43 +00:00 committed by Vesa Juvonen
parent 89cd64eadb
commit 99ea9eefde
38 changed files with 14166 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

32
samples/react-project-online/.gitignore vendored Normal file
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,8 @@
{
"@microsoft/generator-sharepoint": {
"version": "1.3.2",
"libraryName": "react-project-online",
"libraryId": "d6729fd9-103c-42c8-8ee5-17760e4ab92f",
"environment": "spo"
}
}

View File

@ -0,0 +1,54 @@
# React Project Online
## Summary
This sample shows how to use SPFx to consume data from the Project Online REST API. The code uses Placeholder and ListView [reusable controls](https://github.com/SharePoint/sp-dev-fx-controls-react) to create a better experience to the end user.
The web part is intended to be used on a project site within PWA site collection, as the web url used for the rest calls is being taken from the web part context object. To use this web part outside of the PWA site collection, just add a new property to the web part to allow the PWA site collection url to be configured (or when provisioning through a provisioning mechanist).
The web part is currently returning project tasks as a simple proof of concept.
![Demo](./assets/Preview.gif)
## Used SharePoint Framework Version
![drop](https://img.shields.io/badge/version-GA-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)
* [Project Online](https://dev.office.com/docs/add-ins/overview/office-add-ins?product=project)
## Prerequisites
- Office 365 subscription with SharePoint Online and Project Online licence
- SharePoint Framework [development environment](https://dev.office.com/sharepoint/docs/spfx/set-up-your-development-environment) already set up.
-Project site with some tasks available.
## Solution
Solution|Author(s)
--------|---------
react-project-online|Joel Rodrigues
## Version history
Version|Date|Comments
-------|----|--------
1.0|October 29, 2017|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
This Web Part illustrates the following concepts on top of the SharePoint Framework:
-Using the SharePoint rest API for querying web properties.
-Using the Project Online rest API for retrieving project tasks.

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View File

@ -0,0 +1,19 @@
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"react-project-online-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/reactProjectOnline/ReactProjectOnlineWebPart.js",
"manifest": "./src/webparts/reactProjectOnline/ReactProjectOnlineWebPart.manifest.json"
}
]
}
},
"externals": {},
"localizedResources": {
"ReactProjectOnlineWebPartStrings": "lib/webparts/reactProjectOnline/loc/{locale}.js",
"ControlStrings": "./node_modules/@pnp/spfx-controls-react/lib/loc/{locale}.js"
}
}

View File

@ -0,0 +1,4 @@
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/copy-assets.schema.json",
"deployCdnPath": "temp/deploy"
}

View File

@ -0,0 +1,7 @@
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
"workingDir": "./temp/deploy/",
"account": "<!-- STORAGE ACCOUNT NAME -->",
"container": "react-project-online",
"accessKey": "<!-- ACCESS KEY -->"
}

View File

@ -0,0 +1,12 @@
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "react-project-online-client-side-solution",
"id": "d6729fd9-103c-42c8-8ee5-17760e4ab92f",
"version": "1.0.0.0",
"skipFeatureDeployment": true
},
"paths": {
"zippedPackage": "solution/react-project-online.sppkg"
}
}

View File

@ -0,0 +1,10 @@
{
"$schema": "https://dev.office.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,45 @@
{
"$schema": "https://dev.office.com/json-schemas/core-build/tslint.schema.json",
// Display errors as warnings
"displayAsWarning": true,
// The TSLint task may have been configured with several custom lint rules
// before this config file is read (for example lint rules from the tslint-microsoft-contrib
// project). If true, this flag will deactivate any of these rules.
"removeExistingRules": true,
// When true, the TSLint task is configured with some default TSLint "rules.":
"useDefaultConfigAsBase": false,
// Since removeExistingRules=true and useDefaultConfigAsBase=false, there will be no lint rules
// which are active, other than the list of rules below.
"lintConfig": {
// Opt-in to Lint rules which help to eliminate bugs in JavaScript
"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-case": true,
"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,
"valid-typeof": true,
"variable-name": false,
"whitespace": false
}
}
}

View File

@ -0,0 +1,4 @@
{
"$schema": "https://dev.office.com/json-schemas/spfx-build/write-manifests.schema.json",
"cdnBasePath": "<!-- PATH TO CDN -->"
}

View File

@ -0,0 +1,6 @@
'use strict';
const gulp = require('gulp');
const build = require('@microsoft/sp-build-web');
build.initialize(gulp);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,36 @@
{
"name": "react-project-online",
"version": "0.0.1",
"private": true,
"engines": {
"node": ">=0.10.0"
},
"scripts": {
"build": "gulp bundle",
"clean": "gulp clean",
"test": "gulp test"
},
"dependencies": {
"@microsoft/sp-core-library": "~1.3.0",
"@microsoft/sp-lodash-subset": "~1.3.0",
"@microsoft/sp-webpart-base": "~1.3.0",
"@pnp/spfx-controls-react": "1.0.0-beta.6",
"@types/react": "15.0.38",
"@types/react-addons-shallow-compare": "0.14.17",
"@types/react-addons-test-utils": "0.14.15",
"@types/react-addons-update": "0.14.14",
"@types/react-dom": "0.14.18",
"@types/webpack-env": ">=1.12.1 <1.14.0",
"react": "15.4.2",
"react-dom": "15.4.2",
"sp-pnp-js": "3.0.1"
},
"devDependencies": {
"@microsoft/sp-build-web": "~1.3.0",
"@microsoft/sp-module-interfaces": "~1.3.0",
"@microsoft/sp-webpart-workbench": "~1.3.0",
"gulp": "~3.9.1",
"@types/chai": ">=3.4.34 <3.6.0",
"@types/mocha": ">=2.2.33 <2.6.0"
}
}

View File

@ -0,0 +1,4 @@
export interface IPOTask {
Id?: string;
Name?: string;
}

View File

@ -0,0 +1 @@
export * from './IPOTask';

View File

@ -0,0 +1,5 @@
import { IPOTask } from "./../interfaces";
export interface IPODataService {
GetProjectTasks(webUrl: string, projectId: string, selectFields: string[], filter: string, orderBy: string, top: number): Promise<IPOTask[]>;
}

View File

@ -0,0 +1,4 @@
export interface ISPDataService {
GetWebProperties(webUrl: string, selectFields: string[]): Promise<any>;
}

View File

@ -0,0 +1,59 @@
import { IWebPartContext } from '@microsoft/sp-webpart-base';
import {
SPHttpClient,
SPHttpClientBatch,
SPHttpClientResponse
} from '@microsoft/sp-http';
import {
Logger,
ConsoleListener,
LogLevel
} from 'sp-pnp-js';
import { IPODataService } from ".";
import { IPOTask } from "./../interfaces";
export class PODataService implements IPODataService {
private _webPartContext: IWebPartContext;
constructor(logLevel: LogLevel, webPartContext: IWebPartContext) {
// setup logger
Logger.subscribe(new ConsoleListener());
Logger.activeLogLevel = logLevel;
// set web part context
this._webPartContext = webPartContext;
}
public set webPartContext(value: IWebPartContext) {
this._webPartContext = value;
}
public get webPartContext(): IWebPartContext {
return this._webPartContext;
}
public async GetProjectTasks(webUrl: string, projectId: string, selectFields: string[], filter: string, orderBy: string, top: number): Promise<IPOTask[]> {
return this._getProjectTasks(webUrl, projectId, selectFields, filter, orderBy, top);
}
private async _getProjectTasks(webUrl: string, projectId: string, selectFields: string[], filter: string, orderBy: string, top: number): Promise<IPOTask[]> {
let data: IPOTask[] = [];
const select = selectFields.join(',');
try {
const response: SPHttpClientResponse = await this._webPartContext.spHttpClient.get(webUrl + `/_api/ProjectServer/Projects('${projectId}')/Tasks()?$select=${select}`, SPHttpClient.configurations.v1);
if (response) {
const jsonData: any = await response.json();
if (jsonData.value) {
data = jsonData.value;
}
}
} catch (error) {
Logger.write('Error loading project tasks: ' + error, LogLevel.Error);
}
return data;
}
}

View File

@ -0,0 +1,26 @@
import {
Logger,
ConsoleListener,
LogLevel
} from 'sp-pnp-js';
import { IPODataService } from ".";
import { IPOTask } from "./../interfaces";
export class POMockDataService implements IPODataService {
constructor(logLevel: LogLevel) {
// setup logger
Logger.subscribe(new ConsoleListener());
Logger.activeLogLevel = logLevel;
}
public async GetProjectTasks(webUrl: string, projectId: string, selectFields: string[], filter: string, orderBy: string, top: number): Promise<IPOTask[]> {
return this._getListItems(webUrl, projectId, selectFields, filter, orderBy, top);
}
private async _getListItems(webUrl: string, projectId: string, selectFields: string[], filter: string, orderBy: string, top: number): Promise<IPOTask[]> {
return null;
}
}

View File

@ -0,0 +1,48 @@
import {
Logger,
ConsoleListener,
LogLevel,
sp,
SearchQuery,
SearchResults,
Web,
ItemAddResult
} from 'sp-pnp-js';
import { ISPDataService } from ".";
export class SPDataService implements ISPDataService {
constructor(logLevel: LogLevel) {
// setup logger
Logger.subscribe(new ConsoleListener());
Logger.activeLogLevel = logLevel;
}
public async GetWebProperties(webUrl: string, selectFields: string[]): Promise<any> {
return this._getWebProperties(webUrl, selectFields);
}
private async _getWebProperties(webUrl: string, selectFields: string[]): Promise<any> {
let web = new Web(webUrl);
let data: any = null;
// prefix all properties with the expanded field
selectFields.forEach((value, index, array) => {
array[index] = "AllProperties/" + value;
});
const select = selectFields.join(',');
try {
data = await web
.select(select)
.expand('AllProperties')
.usingCaching()
.get();
} catch (error) {
Logger.write('Error loading web properties: ' + error, LogLevel.Error);
}
return data.AllProperties;
}
}

View File

@ -0,0 +1,25 @@
import {
Logger,
ConsoleListener,
LogLevel
} from 'sp-pnp-js';
import { ISPDataService } from ".";
export class SPMockDataService implements ISPDataService {
constructor(logLevel: LogLevel) {
// setup logger
Logger.subscribe(new ConsoleListener());
Logger.activeLogLevel = logLevel;
}
public async GetWebProperties(webUrl: string, selectFields: string[]): Promise<any> {
return this._getWebProperties(webUrl, selectFields);
}
private async _getWebProperties(webUrl: string, selectFields: string[]): Promise<any> {
return null;
}
}

View File

@ -0,0 +1,6 @@
export * from './ISPDataService';
export * from './SPDataService';
export * from './SPMockDataService';
export * from './IPODataService';
export * from './PODataService';
export * from './POMockDataService';

View File

@ -0,0 +1,6 @@
import { LogLevel } from 'sp-pnp-js';
export interface IReactProjectOnlineWebPartProps {
dataSourceId: string;
logLevel: LogLevel;
}

View File

@ -0,0 +1,26 @@
{
"$schema": "https://dev.office.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "9dd62689-0ed4-4b35-82e0-848742751bdc",
"alias": "ReactProjectOnlineWebPart",
"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,
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other" },
"title": { "default": "React Project Online Sample" },
"description": { "default": "Sample web part to demonstrate how to retrieve Project Online data using REST" },
"officeFabricIconFontName": "Page",
"properties": {
"logLevel": 99
}
}]
}

View File

@ -0,0 +1,134 @@
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { Version, Environment, EnvironmentType } from '@microsoft/sp-core-library';
import {
BaseClientSideWebPart,
IPropertyPaneConfiguration,
PropertyPaneTextField,
PropertyPaneDropdown
} from '@microsoft/sp-webpart-base';
import { LogLevel } from 'sp-pnp-js';
import * as strings from 'ReactProjectOnlineWebPartStrings';
import { IReactProjectOnlineWebPartProps } from './IReactProjectOnlineWebPartProps';
import ReactProjectOnline from './components/ReactProjectOnline';
import { IReactProjectOnlineProps } from './components/IReactProjectOnlineProps';
import {
ISPDataService, SPDataService, SPMockDataService,
IPODataService, PODataService, POMockDataService
} from "./../../shared/services";
export default class ReactProjectOnlineWebPart extends BaseClientSideWebPart<IReactProjectOnlineWebPartProps> {
private _spDataService: ISPDataService;
private _poDataService: IPODataService;
public onInit(): Promise<void> {
this.context.statusRenderer.displayLoadingIndicator(this.domElement, strings.TitleFieldLabel);
/*
Create the appropriate data provider depending on where the web part is running.
The DEBUG flag will ensure the mock data provider is not bundled with the web part when you package the solution for distribution,
that is, using the --ship flag with the package-solution gulp command.
*/
if (DEBUG && Environment.type === EnvironmentType.Local) {
// Local environment
this._spDataService = new SPMockDataService(this.properties.logLevel);
this._poDataService = new POMockDataService(this.properties.logLevel);
} else {
this._spDataService = new SPDataService(this.properties.logLevel);
this._poDataService = new PODataService(this.properties.logLevel, this.context);
}
this.context.statusRenderer.clearLoadingIndicator(this.domElement);
return super.onInit();
}
public render(): void {
const element: React.ReactElement<IReactProjectOnlineProps> = React.createElement(
ReactProjectOnline,
{
baseProperties: this.properties,
spDataService: this._spDataService,
poDataService: this._poDataService,
webPartContext: this.context
}
);
ReactDom.render(element, this.domElement);
}
protected get dataVersion(): Version {
return Version.parse('1.0');
}
protected async onPropertyPaneConfigurationStart(): Promise<any> {
// load data only when user opens the property pane to configure webpart
if (this.properties.dataSourceId.length === 0) {
await this._getProjectID();
}
super.onPropertyPaneConfigurationStart();
}
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: strings.PropertyPaneDescription
},
groups: [
{
groupName: strings.BasicGroupName,
groupFields: [
PropertyPaneTextField('dataSourceId', {
label: strings.DataSourceIdFieldLabel,
disabled: true
})
]
},
{
groupName: strings.ConfigurationGroupName,
groupFields: [
PropertyPaneDropdown('logLevel', {
label: strings.LogLevelLabel,
selectedKey: this.properties.logLevel,
options: [
{ key: LogLevel.Off, text: 'Off' },
{ key: LogLevel.Error, text: 'Error' },
{ key: LogLevel.Warning, text: 'Warning' },
{ key: LogLevel.Info, text: 'Info' },
{ key: LogLevel.Verbose, text: 'Verbose' }
]
})
]
}
]
}
]
};
}
private async _getProjectID(): Promise<string> {
let id: string = null;
const webUrl = this.context.pageContext.web.absoluteUrl;
const selectWebProperties = ['MSPWAPROJUID'];
try {
// get project ID
const projectUID: any = await this._spDataService.GetWebProperties(webUrl, selectWebProperties);
if (projectUID) {
this.properties.dataSourceId = projectUID.MSPWAPROJUID;
this.context.propertyPane.refresh();
}
} catch (error) {
console.log('Error getting project ID from data service: ', error);
}
return id;
}
}

View File

@ -0,0 +1,10 @@
import { IReactProjectOnlineWebPartProps } from "./../IReactProjectOnlineWebPartProps";
import { ISPDataService, IPODataService } from "./../../../shared/services";
import { IWebPartContext } from '@microsoft/sp-webpart-base';
export interface IReactProjectOnlineProps {
baseProperties: IReactProjectOnlineWebPartProps;
spDataService: ISPDataService;
poDataService: IPODataService;
webPartContext: IWebPartContext;
}

View File

@ -0,0 +1,52 @@
.reactProjectOnline {
.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 {
padding: 20px;
}
.listItem {
max-width: 715px;
margin: 5px auto 5px auto;
box-shadow: 0 0 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
}
.button {
// Our button
text-decoration: none;
height: 32px;
// Primary Button
min-width: 80px;
background-color: "[theme:themePrimary, default:#0078d7]";
border-color: "[theme:themePrimary, default:#0078d7]";
color: #ffffff;
// 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: 14px;
font-weight: 400;
border-width: 0;
text-align: center;
cursor: pointer;
display: inline-block;
padding: 0 16px;
.label {
font-weight: 600;
font-size: 14px;
height: 32px;
line-height: 32px;
margin: 0 4px;
vertical-align: top;
display: inline-block;
}
}
}

View File

@ -0,0 +1,143 @@
import * as React from 'react';
import { Util } from 'sp-pnp-js';
import * as strings from 'ReactProjectOnlineWebPartStrings';
import styles from './ReactProjectOnline.module.scss';
import { ListView, IViewField, SelectionMode } from "@pnp/spfx-controls-react/lib/ListView";
import { Placeholder } from "@pnp/spfx-controls-react/lib/Placeholder";
import { IReactProjectOnlineProps, ReactProjectOnlineState } from '.';
import { IPOTask } from './../../../shared/interfaces';
export default class ReactProjectOnline extends React.Component<IReactProjectOnlineProps, ReactProjectOnlineState> {
private _maxResults = 1000;
private _taskItems: IPOTask[] = [];
private _selectedTaskItems: IPOTask[] = [];
constructor(props: IReactProjectOnlineProps) {
super(props);
// evaluate if configuration is required, and if so, display a placeholder
const showPlaceHolder = Util.stringIsNullOrEmpty(this.props.baseProperties.dataSourceId);
// initialise state
this.state = {
dataLoaded: false,
showPlaceHolder: showPlaceHolder
};
// bind functions to set the correct context
this._onConfigure = this._onConfigure.bind(this);
this._getTaskSelection = this._getTaskSelection.bind(this);
}
// componentDidMount() is invoked immediately after a component is mounted. Initialization that requires DOM nodes should go here.
// If you need to load data from a remote endpoint, this is a good place to instantiate the network request.
// Setting state in this method will trigger a re-rendering.
public async componentDidMount() {
this.props.webPartContext.statusRenderer.displayLoadingIndicator(document.getElementsByClassName(styles.reactProjectOnline)[0], strings.TitleFieldLabel);
// load data and update state
if (!Util.stringIsNullOrEmpty(this.props.baseProperties.dataSourceId)) {
this._taskItems = await this._getTaskItems();
this.setState({
dataLoaded: true
});
}
this.props.webPartContext.statusRenderer.clearLoadingIndicator(document.getElementsByClassName(styles.reactProjectOnline)[0]);
}
// componentWillReceiveProps() is invoked before a mounted component receives new props.
// If you need to update the state in response to prop changes (for example, to reset it), you may compare this.props and nextProps and perform
// state transitions using this.setState() in this method.
public async componentWillReceiveProps(props: IReactProjectOnlineProps) {
// load data and update state
if (!Util.stringIsNullOrEmpty(this.props.baseProperties.dataSourceId)) {
this._taskItems = await this._getTaskItems();
this.setState({
showPlaceHolder: false,
dataLoaded: true
});
} else {
this.setState({
showPlaceHolder: true,
dataLoaded: false
});
}
}
public render(): React.ReactElement<IReactProjectOnlineProps> {
// Fields that need to be viewed in the task listview
const taskViewFields: IViewField[] = [
{
name: 'Name',
displayName: 'Name',
sorting: true
}
];
return (
<section>
{this.state.showPlaceHolder &&
<Placeholder
iconName='Edit'
iconText='Configure your web part'
description='Please configure the web part.'
buttonLabel='Configure'
onConfigure={this._onConfigure} />
}
<div className={styles.reactProjectOnline}>
{this.state.dataLoaded &&
<div className={styles.container}>
<ListView
items={this._taskItems}
viewFields={taskViewFields}
compact={true}
selectionMode={SelectionMode.single}
selection={this._getTaskSelection} />
</div>
}
</div>
</section>
);
}
private _onConfigure() {
// Context of the web part
this.props.webPartContext.propertyPane.open();
}
private _getTaskSelection(items: IPOTask[]) {
this._selectedTaskItems = items;
console.log(this._selectedTaskItems);
}
private async _getTaskItems(): Promise<IPOTask[]> {
let items: IPOTask[] = [];
const webUrl = this.props.webPartContext.pageContext.web.absoluteUrl;
const selectFields = ['ID', 'Name'];
const filter = '';
const orderBy = '';
try {
// get tasks
items = await this.props.poDataService.GetProjectTasks(
webUrl,
this.props.baseProperties.dataSourceId,
selectFields,
filter,
orderBy,
this._maxResults
) as IPOTask[];
} catch (error) {
console.log('Error loading tasks data from data service: ', error);
}
return items;
}
}

View File

@ -0,0 +1,4 @@
export interface ReactProjectOnlineState {
showPlaceHolder?: boolean;
dataLoaded?: boolean;
}

View File

@ -0,0 +1,3 @@
export * from './IReactProjectOnlineProps';
export * from './ReactProjectOnlineState';
export * from './ReactProjectOnline';

View File

@ -0,0 +1,10 @@
define([], function() {
return {
"PropertyPaneDescription": "React Project Online sample web part properties",
"BasicGroupName": "Basic Configuration",
"TitleFieldLabel": "React Project Online Sample",
"DataSourceIdFieldLabel": "Project Id (MSPWAPROJUID)",
"ConfigurationGroupName": "Advanced Configuration",
"LogLevelLabel": "Log Level"
}
});

View File

@ -0,0 +1,13 @@
declare interface IReactProjectOnlineWebPartStrings {
PropertyPaneDescription: string;
BasicGroupName: string;
TitleFieldLabel: string;
DataSourceIdFieldLabel: string;
ConfigurationGroupName: string;
LogLevelLabel: string;
}
declare module 'ReactProjectOnlineWebPartStrings' {
const strings: IReactProjectOnlineWebPartStrings;
export = strings;
}

View File

@ -0,0 +1,9 @@
/// <reference types="mocha" />
import { assert } from 'chai';
describe('ReactProjectOnlineWebPart', () => {
it('should do something', () => {
assert.ok(true);
});
});

View File

@ -0,0 +1,16 @@
{
"compilerOptions": {
"target": "es5",
"forceConsistentCasingInFileNames": true,
"module": "commonjs",
"jsx": "react",
"declaration": true,
"sourceMap": true,
"experimentalDecorators": true,
"types": [
"es6-promise",
"es6-collections",
"webpack-env"
]
}
}

View File

@ -0,0 +1,11 @@
// Type definitions for Microsoft ODSP projects
// Project: ODSP
/* Global definition for UNIT_TEST builds
Code that is wrapped inside an if(UNIT_TEST) {...}
block will not be included in the final bundle when the
--ship flag is specified */
declare const UNIT_TEST: boolean;
/* Global defintion for SPO builds */
declare const DATACENTER: boolean;

View File

@ -0,0 +1 @@
/// <reference path="@ms/odsp.d.ts" />