New sample Add ToDo Task from Email (Outlook)
This commit is contained in:
parent
e0fa5f1b25
commit
e43f35704a
|
@ -0,0 +1,25 @@
|
|||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
|
||||
[*]
|
||||
|
||||
# change these settings to your own preference
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# we recommend you to keep these unchanged
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[{package,bower}.json]
|
||||
indent_style = space
|
||||
indent_size = 2
|
|
@ -0,0 +1,32 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
|
||||
# Build generated files
|
||||
dist
|
||||
lib
|
||||
solution
|
||||
temp
|
||||
*.sppkg
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# OSX
|
||||
.DS_Store
|
||||
|
||||
# Visual Studio files
|
||||
.ntvs_analysis.dat
|
||||
.vs
|
||||
bin
|
||||
obj
|
||||
|
||||
# Resx Generated Code
|
||||
*.resx.ts
|
||||
|
||||
# Styles Generated Code
|
||||
*.scss.ts
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"plusBeta": true,
|
||||
"isCreatingSolution": true,
|
||||
"environment": "spo",
|
||||
"version": "1.10.0",
|
||||
"libraryName": "react-outlook-add-todo-task",
|
||||
"libraryId": "3702cca0-5492-4bb3-b393-3fbdd553e79a",
|
||||
"packageManager": "npm",
|
||||
"isDomainIsolated": false,
|
||||
"componentType": "webpart"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
# Create To Do Task from Email (Outlook Add in)
|
||||
|
||||
## Summary
|
||||
This webpart allows us to create a new To Do task using the new ToDo MS Graph endpoint. If deployed as an Outlook Add In, the Task title comes from email subject. Let´s say this is similar to the OOTB "Flag" action, but here you can select the ToDo List where to store the Task, and you can modify the Title before adding it.
|
||||
|
||||
![Create ToDo task](./assets/spfx-todo-outlook.gif)
|
||||
|
||||
## Graph To-Do Preview endpoints
|
||||
|
||||
As of today, To Do endpoint is not very well documented yet. It was presented in latest Build 2020. Here are some of the basic operations. You can get more information and see the Build session from this link: [https://developer.microsoft.com/en-us/office/blogs/introducing-the-new-microsoft-graph-to-do-api/](https://developer.microsoft.com/en-us/office/blogs/introducing-the-new-microsoft-graph-to-do-api/)
|
||||
|
||||
### Get lists
|
||||
GET https://graph.microsoft.com/beta/me/todo/lists
|
||||
|
||||
### Create new List
|
||||
|
||||
POST https://graph.microsoft.com/beta/me/todo/lists
|
||||
|
||||
```json
|
||||
{
|
||||
displayName: "My new List"
|
||||
}
|
||||
```
|
||||
|
||||
### Get tasks in list
|
||||
GET https://graph.microsoft.com/beta/me/todo/lists/{listId}/tasks
|
||||
|
||||
### Create new Task in List
|
||||
POST https://graph.microsoft.com/beta/me/todo/lists/{listId}/tasks
|
||||
|
||||
```json
|
||||
{
|
||||
"importance": "high",
|
||||
"status": "notStarted",
|
||||
"title": "New task to do",
|
||||
"body": {
|
||||
"content": "You have a new task to do",
|
||||
"contentType": "text"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
|
||||
![SPFx v1.10.0](https://img.shields.io/badge/SPFx-1.10.0-green.svg)
|
||||
|
||||
## Solution
|
||||
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
react-outlook-add-todo-task|Luis Mañez (MVP, [ClearPeople](http://www.clearpeople.com), @luismanez)
|
||||
|
||||
## Version history
|
||||
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0.0|Jun 3, 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 repo
|
||||
* gulp bundle --ship
|
||||
* gulp package-solution --ship
|
||||
* deploy package to SharePoint App Catalog (check tenant deploy)
|
||||
* Using O365 CLI to configure MS Graph permissions to allow creating ToDo tasks
|
||||
```ps
|
||||
spo serviceprincipal grant add --resource "Microsoft Graph" --scope "Tasks.ReadWrite"
|
||||
```
|
||||
* deploy spfx solution as Outlook add-in following instructions here: [https://docs.microsoft.com/en-us/sharepoint/dev/spfx/office-addins-create#deployment-of-your-add-in](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/office-addins-create#deployment-of-your-add-in)
|
||||
|
||||
## Features
|
||||
|
||||
This sample illustrates the following concepts on top of the SharePoint Framework:
|
||||
|
||||
* New ToDo MS Graph endpoint
|
||||
* Using __MSGraphClient__
|
||||
* Outlook SPFx add-in
|
||||
* Using _async / await_ for the async calls
|
||||
* FluentUI components
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-outlook-add-todo-task" />
|
Binary file not shown.
After Width: | Height: | Size: 13 MiB |
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
|
||||
"version": "2.0",
|
||||
"bundles": {
|
||||
"create-task-web-part": {
|
||||
"components": [
|
||||
{
|
||||
"entrypoint": "./lib/webparts/createTask/CreateTaskWebPart.js",
|
||||
"manifest": "./src/webparts/createTask/CreateTaskWebPart.manifest.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"externals": {},
|
||||
"localizedResources": {
|
||||
"CreateTaskWebPartStrings": "lib/webparts/createTask/loc/{locale}.js"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json",
|
||||
"deployCdnPath": "temp/deploy"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
|
||||
"workingDir": "./temp/deploy/",
|
||||
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
||||
"container": "react-outlook-add-todo-task",
|
||||
"accessKey": "<!-- ACCESS KEY -->"
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
|
||||
"solution": {
|
||||
"name": "react-outlook-add-todo-task-client-side-solution",
|
||||
"id": "3702cca0-5492-4bb3-b393-3fbdd553e79a",
|
||||
"version": "1.0.0.0",
|
||||
"includeClientSideAssets": true,
|
||||
"skipFeatureDeployment": true,
|
||||
"isDomainIsolated": false
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/react-outlook-add-todo-task.sppkg"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
|
||||
"port": 4321,
|
||||
"https": true,
|
||||
"initialPage": "https://localhost:5432/workbench",
|
||||
"api": {
|
||||
"port": 5432,
|
||||
"entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/write-manifests.schema.json",
|
||||
"cdnBasePath": "<!-- PATH TO CDN -->"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
'use strict';
|
||||
|
||||
const build = require('@microsoft/sp-build-web');
|
||||
|
||||
build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
|
||||
|
||||
build.initialize(require('gulp'));
|
|
@ -0,0 +1,91 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<OfficeApp xmlns="http://schemas.microsoft.com/office/appforoffice/1.1"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:bt="http://schemas.microsoft.com/office/officeappbasictypes/1.0"
|
||||
xmlns:mailappor="http://schemas.microsoft.com/office/mailappversionoverrides/1.0"
|
||||
xsi:type="MailApp">
|
||||
<Id>d459dda9-d0a0-4e5c-b996-1e48327a306d</Id>
|
||||
<Version>1.0.0.0</Version>
|
||||
<ProviderName>Luis Manez MVP</ProviderName>
|
||||
<DefaultLocale>en-US</DefaultLocale>
|
||||
<DisplayName DefaultValue="To Do PnP"/>
|
||||
<Description DefaultValue="Add To Do tasks from an email"/>
|
||||
<IconUrl DefaultValue="https://cdn.graph.office.net/prod/media/shared/addin-icon.png"/>
|
||||
<HighResolutionIconUrl DefaultValue="https://cdn.graph.office.net/prod/media/shared/addin-icon.png"/>
|
||||
<SupportUrl DefaultValue="https://localhost:4321/help"/>
|
||||
<AppDomains>
|
||||
<AppDomain>https://login.microsoftonline.com</AppDomain>
|
||||
<AppDomain>https://login.windows.net</AppDomain>
|
||||
</AppDomains>
|
||||
<Hosts>
|
||||
<Host Name="Mailbox" />
|
||||
</Hosts>
|
||||
<Requirements>
|
||||
<Sets>
|
||||
<Set Name="Mailbox" MinVersion="1.4" />
|
||||
<Set Name="SharePointHostedAddin" MinVersion="1.1" />
|
||||
</Sets>
|
||||
</Requirements>
|
||||
<FormSettings>
|
||||
<Form xsi:type="ItemRead">
|
||||
<DesktopSettings>
|
||||
<SourceLocation DefaultValue="https://_SharePointTenantUrl_/_layouts/15/outlookhostedapp.aspx?componentId=d459dda9-d0a0-4e5c-b996-1e48327a306d"/>
|
||||
<RequestedHeight>250</RequestedHeight>
|
||||
</DesktopSettings>
|
||||
</Form>
|
||||
</FormSettings>
|
||||
<Permissions>ReadWriteMailbox</Permissions>
|
||||
<Rule xsi:type="RuleCollection" Mode="Or">
|
||||
<Rule xsi:type="ItemIs" ItemType="Message" FormType="Read" />
|
||||
</Rule>
|
||||
<DisableEntityHighlighting>false</DisableEntityHighlighting>
|
||||
<VersionOverrides xmlns="http://schemas.microsoft.com/office/mailappversionoverrides" xsi:type="VersionOverridesV1_0">
|
||||
<VersionOverrides xmlns="http://schemas.microsoft.com/office/mailappversionoverrides/1.1" xsi:type="VersionOverridesV1_1">
|
||||
<Hosts>
|
||||
<Host xsi:type="MailHost">
|
||||
<DesktopFormFactor>
|
||||
<ExtensionPoint xsi:type="MessageReadCommandSurface">
|
||||
<OfficeTab id="TabDefault">
|
||||
<Group id="msgReadGroup">
|
||||
<Label resid="GroupLabel" />
|
||||
<Control xsi:type="Button" id="msgReadOpenPaneButton">
|
||||
<Label resid="TaskpaneButton.Label" />
|
||||
<Supertip>
|
||||
<Title resid="TaskpaneButton.Label" />
|
||||
<Description resid="TaskpaneButton.Tooltip" />
|
||||
</Supertip>
|
||||
<Icon>
|
||||
<bt:Image size="16" resid="Icon.16x16" />
|
||||
<bt:Image size="32" resid="Icon.32x32" />
|
||||
<bt:Image size="80" resid="Icon.80x80" />
|
||||
</Icon>
|
||||
<Action xsi:type="ShowTaskpane">
|
||||
<SourceLocation resid="Taskpane.Url" />
|
||||
</Action>
|
||||
</Control>
|
||||
</Group>
|
||||
</OfficeTab>
|
||||
</ExtensionPoint>
|
||||
</DesktopFormFactor>
|
||||
</Host>
|
||||
</Hosts>
|
||||
<Resources>
|
||||
<bt:Images>
|
||||
<bt:Image id="Icon.16x16" DefaultValue="https://cdn.graph.office.net/prod/media/shared/addin-icon.png"/>
|
||||
<bt:Image id="Icon.32x32" DefaultValue="https://cdn.graph.office.net/prod/media/shared/addin-icon.png"/>
|
||||
<bt:Image id="Icon.80x80" DefaultValue="https://cdn.graph.office.net/prod/media/shared/addin-icon.png"/>
|
||||
</bt:Images>
|
||||
<bt:Urls>
|
||||
<bt:Url id="Taskpane.Url" DefaultValue="https://_SharePointTenantUrl_/_layouts/15/outlookhostedapp.aspx?componentId=d459dda9-d0a0-4e5c-b996-1e48327a306d" />
|
||||
</bt:Urls>
|
||||
<bt:ShortStrings>
|
||||
<bt:String id="GroupLabel" DefaultValue="Add-in groupLabel"/>
|
||||
<bt:String id="TaskpaneButton.Label" DefaultValue="Show Taskpane"/>
|
||||
</bt:ShortStrings>
|
||||
<bt:LongStrings>
|
||||
<bt:String id="TaskpaneButton.Tooltip" DefaultValue="Opens taskpane."/>
|
||||
</bt:LongStrings>
|
||||
</Resources>
|
||||
</VersionOverrides>
|
||||
</VersionOverrides>
|
||||
</OfficeApp>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"name": "react-outlook-add-todo-task",
|
||||
"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": {
|
||||
"react": "16.8.5",
|
||||
"react-dom": "16.8.5",
|
||||
"@types/react": "16.8.8",
|
||||
"@types/react-dom": "16.8.3",
|
||||
"office-ui-fabric-react": "6.189.2",
|
||||
"@microsoft/sp-core-library": "1.10.0-plusbeta",
|
||||
"@microsoft/sp-property-pane": "1.10.0-plusbeta",
|
||||
"@microsoft/sp-webpart-base": "1.10.0-plusbeta",
|
||||
"@microsoft/sp-lodash-subset": "1.10.0-plusbeta",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.10.0-plusbeta",
|
||||
"@types/webpack-env": "1.13.1",
|
||||
"@types/es6-promise": "0.0.33"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "16.8.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/sp-build-web": "1.10.0-plusbeta",
|
||||
"@microsoft/sp-tslint-rules": "1.10.0-plusbeta",
|
||||
"@microsoft/sp-module-interfaces": "1.10.0-plusbeta",
|
||||
"@microsoft/sp-webpart-workbench": "1.10.0-plusbeta",
|
||||
"@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"
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
// A file is required to be in the root of the /src directory by the TypeScript compiler
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
|
||||
"id": "d459dda9-d0a0-4e5c-b996-1e48327a306d",
|
||||
"alias": "CreateTaskWebPart",
|
||||
"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": "CreateTask" },
|
||||
"description": { "default": "Add new Task to MS To Do from an Email" },
|
||||
"officeFabricIconFontName": "Page",
|
||||
"properties": {
|
||||
"description": "CreateTask"
|
||||
}
|
||||
}]
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
import * as React from 'react';
|
||||
import * as ReactDom from 'react-dom';
|
||||
import { Version } from '@microsoft/sp-core-library';
|
||||
import {
|
||||
IPropertyPaneConfiguration,
|
||||
PropertyPaneTextField
|
||||
} from '@microsoft/sp-property-pane';
|
||||
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
|
||||
|
||||
import { MSGraphClient } from '@microsoft/sp-http';
|
||||
|
||||
import * as strings from 'CreateTaskWebPartStrings';
|
||||
import CreateTask from './components/CreateTask';
|
||||
import { ICreateTaskProps } from './components/ICreateTaskProps';
|
||||
import { ICreateTaskContext } from './models/ICreateTaskContext';
|
||||
|
||||
export interface ICreateTaskWebPartProps {
|
||||
}
|
||||
|
||||
export default class CreateTaskWebPart extends BaseClientSideWebPart<ICreateTaskWebPartProps> {
|
||||
|
||||
private _graphHttpClient: MSGraphClient;
|
||||
|
||||
protected onInit(): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
this.context.msGraphClientFactory.getClient().then(client => {
|
||||
this._graphHttpClient = client;
|
||||
resolve();
|
||||
}).catch(error => {
|
||||
console.log(error);
|
||||
reject(error);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private _getContext(): ICreateTaskContext {
|
||||
if (this.context.sdks.office) {
|
||||
const mailboxItem: Office.MessageRead = this.context.sdks.office.context.mailbox.item;
|
||||
const context: ICreateTaskContext = {
|
||||
graphHttpClient: this._graphHttpClient,
|
||||
siteUrl: this.context.pageContext.web.absoluteUrl,
|
||||
item: {
|
||||
id: mailboxItem.itemId,
|
||||
subject: mailboxItem.subject,
|
||||
from: mailboxItem.from.emailAddress,
|
||||
to: mailboxItem.to[0].emailAddress
|
||||
}
|
||||
};
|
||||
return context;
|
||||
}
|
||||
else {
|
||||
const context: ICreateTaskContext = {
|
||||
item: null,
|
||||
graphHttpClient: this._graphHttpClient,
|
||||
siteUrl: this.context.pageContext.web.absoluteUrl
|
||||
};
|
||||
return context;
|
||||
}
|
||||
}
|
||||
|
||||
public render(): void {
|
||||
|
||||
const context: ICreateTaskContext = this._getContext();
|
||||
|
||||
const element: React.ReactElement<ICreateTaskProps> = React.createElement(
|
||||
CreateTask,
|
||||
{
|
||||
context: context
|
||||
}
|
||||
);
|
||||
|
||||
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: strings.PropertyPaneDescription
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
groupName: strings.BasicGroupName,
|
||||
groupFields: [
|
||||
PropertyPaneTextField('description', {
|
||||
label: strings.DescriptionFieldLabel
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
@import '~office-ui-fabric-react/dist/sass/References.scss';
|
||||
|
||||
.createTask {
|
||||
.container {
|
||||
max-width: 700px;
|
||||
margin: 0px auto;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.row {
|
||||
@include ms-Grid-row;
|
||||
@include ms-fontColor-white;
|
||||
background-color: $ms-color-themeDark;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.column {
|
||||
@include ms-Grid-col;
|
||||
@include ms-lg10;
|
||||
@include ms-xl8;
|
||||
@include ms-xlPush2;
|
||||
@include ms-lgPush1;
|
||||
}
|
||||
|
||||
.title {
|
||||
@include ms-font-xl;
|
||||
@include ms-fontColor-white;
|
||||
}
|
||||
|
||||
.subTitle {
|
||||
@include ms-font-l;
|
||||
@include ms-fontColor-white;
|
||||
}
|
||||
|
||||
.description {
|
||||
@include ms-font-l;
|
||||
@include ms-fontColor-white;
|
||||
}
|
||||
|
||||
.button {
|
||||
// Our button
|
||||
text-decoration: none;
|
||||
height: 32px;
|
||||
|
||||
// Primary Button
|
||||
min-width: 80px;
|
||||
background-color: $ms-color-themePrimary;
|
||||
border-color: $ms-color-themePrimary;
|
||||
color: $ms-color-white;
|
||||
|
||||
// Basic Button
|
||||
outline: transparent;
|
||||
position: relative;
|
||||
font-family: "Segoe UI WestEuropean","Segoe UI",-apple-system,BlinkMacSystemFont,Roboto,"Helvetica Neue",sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
font-size: $ms-font-size-m;
|
||||
font-weight: $ms-font-weight-regular;
|
||||
border-width: 0;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
padding: 0 16px;
|
||||
|
||||
.label {
|
||||
font-weight: $ms-font-weight-semibold;
|
||||
font-size: $ms-font-size-m;
|
||||
height: 32px;
|
||||
line-height: 32px;
|
||||
margin: 0 4px;
|
||||
vertical-align: top;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,187 @@
|
|||
import * as React from "react";
|
||||
import styles from "./CreateTask.module.scss";
|
||||
import { ICreateTaskProps } from "./ICreateTaskProps";
|
||||
import { ITodoList, ITodoListItem } from "../models/ITodo";
|
||||
import { ICreateTaskState } from "./ICreateTaskState";
|
||||
import {
|
||||
Stack,
|
||||
Dropdown,
|
||||
IDropdownOption,
|
||||
Label,
|
||||
TextField,
|
||||
IStackTokens,
|
||||
IDropdownStyles,
|
||||
PrimaryButton,
|
||||
MessageBar,
|
||||
Link,
|
||||
MessageBarType
|
||||
} from "office-ui-fabric-react";
|
||||
|
||||
import { MSGraphClient } from "@microsoft/sp-http";
|
||||
|
||||
export default class CreateTask extends React.Component<
|
||||
ICreateTaskProps,
|
||||
ICreateTaskState
|
||||
> {
|
||||
constructor(props: ICreateTaskProps) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
listItemAdded: false,
|
||||
selectedList: undefined,
|
||||
todoLists: [],
|
||||
newTaskTitle: this.props.context.item
|
||||
? this.props.context.item.subject
|
||||
: "New Task title here!",
|
||||
showSelectListError: false
|
||||
};
|
||||
|
||||
this._onDropdownChange = this._onDropdownChange.bind(this);
|
||||
this._onChangeNewTaskTitle = this._onChangeNewTaskTitle.bind(this);
|
||||
this._createTask = this._createTask.bind(this);
|
||||
}
|
||||
|
||||
private async _getTodoLists(): Promise<ITodoList[]> {
|
||||
const endpoint: string = "https://graph.microsoft.com/beta/me/todo/lists";
|
||||
const response: any = await this.props.context.graphHttpClient
|
||||
.api(endpoint)
|
||||
.get();
|
||||
const graphResponse: any = response.value;
|
||||
|
||||
const todoLists: ITodoList[] = graphResponse.map((item) => {
|
||||
const list: ITodoList = { id: item.id, displayName: item.displayName };
|
||||
return list;
|
||||
});
|
||||
|
||||
return todoLists;
|
||||
}
|
||||
|
||||
public async componentDidMount(): Promise<void> {
|
||||
const lists: ITodoList[] = await this._getTodoLists();
|
||||
this.setState({
|
||||
todoLists: lists,
|
||||
});
|
||||
}
|
||||
|
||||
public render(): React.ReactElement<ICreateTaskProps> {
|
||||
if (this.state.todoLists.length <= 0) {
|
||||
return <div>Loading to-do lists...</div>;
|
||||
}
|
||||
|
||||
const options: IDropdownOption[] = this.state.todoLists.map((item) => {
|
||||
const dropdownOption: IDropdownOption = {
|
||||
key: item.id,
|
||||
text: item.displayName,
|
||||
};
|
||||
return dropdownOption;
|
||||
});
|
||||
|
||||
const horizontalGapStackTokens: IStackTokens = {
|
||||
childrenGap: 10,
|
||||
};
|
||||
|
||||
const dropdownStyles: Partial<IDropdownStyles> = {
|
||||
dropdown: { width: 200 },
|
||||
};
|
||||
|
||||
const ActionInfo =
|
||||
<MessageBar messageBarType={MessageBarType.success}>
|
||||
Your task has been added!
|
||||
<Link href="https://to-do.office.com/tasks" target="_blank">
|
||||
Open To Do App
|
||||
</Link>
|
||||
</MessageBar>
|
||||
;
|
||||
|
||||
return (
|
||||
<Stack verticalAlign="end" tokens={horizontalGapStackTokens} styles={{root: {padding: '10px'}}}>
|
||||
<Label styles={{root: {fontSize:'18px', fontWeight:'bold'}}}>To Do Outlook SPFx Add-in</Label>
|
||||
<Stack>
|
||||
<Dropdown
|
||||
placeholder="Select a to-do list"
|
||||
options={options}
|
||||
onChange={this._onDropdownChange}
|
||||
styles={dropdownStyles}
|
||||
errorMessage={this.state.showSelectListError ? 'Please select a To Do list' : undefined}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack styles={{ root: { width: "100%" } }}>
|
||||
<TextField
|
||||
value={this.state.newTaskTitle}
|
||||
onChange={this._onChangeNewTaskTitle}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack>
|
||||
<PrimaryButton text="Add Task" onClick={this._createTask} />
|
||||
</Stack>
|
||||
<Stack>
|
||||
{this.state.listItemAdded ? ActionInfo : null}
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
private _onDropdownChange = (
|
||||
event: React.FormEvent<HTMLDivElement>,
|
||||
item: IDropdownOption
|
||||
): void => {
|
||||
const selectedList: ITodoList = this.state.todoLists.filter(
|
||||
(i) => i.id === item.key
|
||||
)[0];
|
||||
|
||||
this.setState({
|
||||
selectedList: selectedList,
|
||||
showSelectListError: false
|
||||
});
|
||||
}
|
||||
|
||||
private _onChangeNewTaskTitle(
|
||||
event: React.FormEvent<HTMLInputElement | HTMLTextAreaElement>,
|
||||
newValue?: string
|
||||
) {
|
||||
if (newValue) {
|
||||
this.setState({
|
||||
newTaskTitle: newValue,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async _createTask(): Promise<void> {
|
||||
try {
|
||||
|
||||
if (!this.state.selectedList) {
|
||||
this.setState({
|
||||
showSelectListError: true
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const listId: string = this.state.selectedList.id;
|
||||
const taskTitle: string = this.state.newTaskTitle;
|
||||
|
||||
const endpoint: string = `https://graph.microsoft.com/beta/me/todo/lists/${listId}/tasks`;
|
||||
|
||||
const body: ITodoListItem = {
|
||||
importance: "high",
|
||||
status: "notStarted",
|
||||
title: taskTitle,
|
||||
body: {
|
||||
content: "You have a new task to do added from SPFx component!",
|
||||
contentType: "text",
|
||||
},
|
||||
};
|
||||
|
||||
var response: any = await this.props.context.graphHttpClient
|
||||
.api(endpoint)
|
||||
.post(body);
|
||||
|
||||
this.setState({
|
||||
listItemAdded: true
|
||||
});
|
||||
|
||||
console.log(response);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
import { ICreateTaskContext } from "../models/ICreateTaskContext";
|
||||
|
||||
export interface ICreateTaskProps {
|
||||
context: ICreateTaskContext;
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
import { ITodoList } from "../models/ITodo";
|
||||
import { Dictionary } from "../models/Dictionary";
|
||||
|
||||
export interface ICreateTaskState {
|
||||
todoLists: ITodoList[];
|
||||
selectedList: ITodoList;
|
||||
newTaskTitle: string;
|
||||
listItemAdded: boolean;
|
||||
showSelectListError: boolean;
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
define([], function() {
|
||||
return {
|
||||
"PropertyPaneDescription": "Description",
|
||||
"BasicGroupName": "Group Name",
|
||||
"DescriptionFieldLabel": "Description Field"
|
||||
}
|
||||
});
|
10
samples/react-outlook-add-todo-task/src/webparts/createTask/loc/mystrings.d.ts
vendored
Normal file
10
samples/react-outlook-add-todo-task/src/webparts/createTask/loc/mystrings.d.ts
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
declare interface ICreateTaskWebPartStrings {
|
||||
PropertyPaneDescription: string;
|
||||
BasicGroupName: string;
|
||||
DescriptionFieldLabel: string;
|
||||
}
|
||||
|
||||
declare module 'CreateTaskWebPartStrings' {
|
||||
const strings: ICreateTaskWebPartStrings;
|
||||
export = strings;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export interface Dictionary<T> {
|
||||
[key: string]: T | undefined;
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
import { MSGraphClient } from '@microsoft/sp-http';
|
||||
import { IMailItem } from "./IMailItem";
|
||||
|
||||
export interface ICreateTaskContext {
|
||||
item: IMailItem;
|
||||
graphHttpClient: MSGraphClient;
|
||||
siteUrl: string;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
export interface IMailItem {
|
||||
id: string;
|
||||
subject: string;
|
||||
from: string;
|
||||
to: string;
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
export interface ITodoList {
|
||||
id: string;
|
||||
displayName: string;
|
||||
}
|
||||
|
||||
export interface ITodoListItem {
|
||||
importance: "low" | "normal" | "high";
|
||||
status: "notStarted" | "inProgress" | "completed" | "waitingOnOthers" | "deferred";
|
||||
title: string;
|
||||
body: {
|
||||
content: string;
|
||||
contentType: "text" | "html";
|
||||
};
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 3.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 1.4 KiB |
|
@ -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"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"extends": "@microsoft/sp-tslint-rules/base-tslint.json",
|
||||
"rules": {
|
||||
"class-name": false,
|
||||
"export-name": false,
|
||||
"forin": false,
|
||||
"label-position": false,
|
||||
"member-access": true,
|
||||
"no-arg": false,
|
||||
"no-console": false,
|
||||
"no-construct": false,
|
||||
"no-duplicate-variable": true,
|
||||
"no-eval": false,
|
||||
"no-function-expression": true,
|
||||
"no-internal-module": true,
|
||||
"no-shadowed-variable": true,
|
||||
"no-switch-case-fall-through": true,
|
||||
"no-unnecessary-semicolons": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-with-statement": true,
|
||||
"semicolon": true,
|
||||
"trailing-comma": false,
|
||||
"typedef": false,
|
||||
"typedef-whitespace": false,
|
||||
"use-named-parameter": true,
|
||||
"variable-name": false,
|
||||
"whitespace": false
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue