added new sample to show how to manage data in onedrive applications folder

This commit is contained in:
Adam 2022-02-21 22:48:28 +01:00
parent 9e2d867a88
commit 69a908ee35
53 changed files with 45062 additions and 0 deletions

View File

@ -0,0 +1,108 @@
# react-save-to-onedrive-app-personal-folder
## Summary
This solution shows how to manage data stored in user application's personal folder in OneDrive which is one of many good methods to store application data/configuration which may be easily used in apps added to SharePoint page or Teams. The solution is built of two compontents. Spfx library which provides the functionality to manage data saved to OneDrive application personal folder and Spfx webpart component which is a very simple solution that uses the library and gets or saves data.
![image](./assets/to-all-sites.png)
when adding solution to appcatalog make it available to all sites
![image](./assets/data-saved-on-onedrive.png)
![image](./assets/data.png)
data saved on onedrive in application personal folder
![image](./assets/in-sharepoint.png)
webpart added to sharepoint page
![image](./assets/in-teams.png)
webpart added to teams
## Compatibility
![SPFx 1.13.0](https://img.shields.io/badge/SPFx-1.13.0-green.svg)
![Node.js v14 | v12](https://img.shields.io/badge/Node.js-v14%20%7C%20v12-green.svg)
![Compatible with SharePoint Online](https://img.shields.io/badge/SharePoint%20Online-Compatible-green.svg)
![Does not work with SharePoint 2019](https://img.shields.io/badge/SharePoint%20Server%202019-Incompatible-red.svg "SharePoint Server 2019 requires SPFx 1.4.1 or lower")
![Does not work with SharePoint 2016 (Feature Pack 2)](https://img.shields.io/badge/SharePoint%20Server%202016%20(Feature%20Pack%202)-Incompatible-red.svg "SharePoint Server 2016 Feature Pack 2 requires SPFx 1.1")
![Local Workbench Unsupported](https://img.shields.io/badge/Local%20Workbench-Unsupported-red.svg "Local workbench is no longer available as of SPFx 1.13 and above")
![Hosted Workbench Compatible](https://img.shields.io/badge/Hosted%20Workbench-Compatible-green.svg)
![Compatible with Remote Containers](https://img.shields.io/badge/Remote%20Containers-Compatible-green.svg)
## Applies to
- [SharePoint Framework](https://aka.ms/spfx)
- [Microsoft 365 tenant](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant)
## Solution
Solution|Author(s)
--------|---------
react-save-to-onedrive-app-personal-folder | [Adam Wójcik](https://github.com/Adam-it)
## Version history
Version|Date|Comments
-------|----|--------
1.0|Februaru 21, 2022|Initial release
## Minimal Path to Awesome
- Clone this repository (or [download this solution as a .ZIP file](https://pnp.github.io/download-partial/?url=https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-save-to-onedrive-app-personal-folder) then unzip it)
- Ensure that you are at the solution folder
- go to library folder
- in the command-line run:
- `npm install`
- `gulp bundle --ship`
- `gulp package-solution --ship`
- Add to AppCatalog and deploy (check option to make this solution available to all sites)
- Approve the MS Graph API permissions in SharePoint Admin page
- go to webpart folder
- in the command-line run:
- `npm install`
- `gulp serve`
- `gulp bundle --ship`
- `gulp package-solution --ship`
- Add to AppCatalog and deploy
> This sample can also be opened with [VS Code Remote Development](https://code.visualstudio.com/docs/remote/remote-overview). Visit https://aka.ms/spfx-devcontainer for further instructions.
## Features
Description of the extension that expands upon high-level summary above.
This extension illustrates the following concepts:
- how to use Spfx library code in webpart
- how to use Microsoft Graph api to use special approot on user OneDrive
- how to save/update data in a json file special approot folder on user OneDrive as a place to keep data a use in SharePoint or Teams
## References
- [Getting started with SharePoint Framework](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant)
- [Building for Microsoft teams](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/build-for-teams-overview)
- [Use Microsoft Graph in your solution](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/using-microsoft-graph-apis)
- [Publish SharePoint Framework applications to the Marketplace](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/publish-to-marketplace-overview)
- [Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) - Guidance, tooling, samples and open-source controls for your Microsoft 365 development
## Help
We do not support samples, but this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues.
If you're having issues building the solution, please run [spfx doctor](https://pnp.github.io/cli-microsoft365/cmd/spfx/spfx-doctor/) from within the solution folder to diagnose incompatibility issues with your environment.
You can try looking at [issues related to this sample](https://github.com/pnp/sp-dev-fx-webparts/issues?q=label%3A%22sample%3A%20react-save-to-onedrive-app-personal-folder%22) to see if anybody else is having the same issues.
You can also try looking at [discussions related to this sample](https://github.com/pnp/sp-dev-fx-webparts/discussions?discussions_q=react-save-to-onedrive-app-personal-folder) and see what the community is saying.
If you encounter any issues while using this sample, [create a new issue](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected%2Csample%3A%20react-save-to-onedrive-app-personal-folder&template=bug-report.yml&sample=react-save-to-onedrive-app-personal-folder&authors=@Adam-it&title=react-save-to-onedrive-app-personal-folder%20-%20).
For questions regarding this sample, [create a new question](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Aquestion%2Csample%3A%20react-save-to-onedrive-app-personal-folder&template=question.yml&sample=react-save-to-onedrive-app-personal-folder&authors=@Adam-it&title=react-save-to-onedrive-app-personal-folder%20-%20).
Finally, if you have an idea for improvement, [make a suggestion](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Aenhancement%2Csample%3A%20react-save-to-onedrive-app-personal-folder&template=suggestion.yml&sample=react-save-to-onedrive-app-personal-folder&authors=@Adam-it&title=react-save-to-onedrive-app-personal-folder%20-%20).
## Disclaimer
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
<img src="https://pnptelemetry.azurewebsites.net/sp-dev-fx-webparts/samples/react-save-to-onedrive-app-personal-folder" />

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

View File

@ -0,0 +1,33 @@
# Logs
logs
*.log
npm-debug.log*
# Dependency directories
node_modules
# Build generated files
dist
lib
release
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,16 @@
!dist
config
gulpfile.js
release
src
temp
tsconfig.json
tslint.json
*.log
.yo-rc.json
.vscode

View File

@ -0,0 +1,16 @@
{
"@microsoft/generator-sharepoint": {
"plusBeta": true,
"isCreatingSolution": true,
"version": "1.14.0-beta.5",
"libraryName": "manage-data",
"libraryId": "cc04d03e-418c-44fc-a125-9fb84d9e9b33",
"environment": "spo",
"packageManager": "npm",
"solutionName": "manage-data",
"solutionShortDescription": "manage-data description",
"skipFeatureDeployment": true,
"isDomainIsolated": false,
"componentType": "library"
}
}

View File

@ -0,0 +1,97 @@
# manage-data
## Summary
This is a Spfx library component which provides functionality to manage data stored in user application's personal folder in OneDrive which is one of many good methods to store application data/configuration which may be easily used in apps added to SharePoint page or Teams.
![image](../assets/to-all-sites.png)
when adding solution to appcatalog make it available to all sites
![image](../assets/data-saved-on-onedrive.png)
![image](../assets/data.png)
data saved on onedrive in application personal folder
## Compatibility
![SPFx 1.13.0](https://img.shields.io/badge/SPFx-1.13.0-green.svg)
![Node.js v14 | v12](https://img.shields.io/badge/Node.js-v14%20%7C%20v12-green.svg)
![Compatible with SharePoint Online](https://img.shields.io/badge/SharePoint%20Online-Compatible-green.svg)
![Does not work with SharePoint 2019](https://img.shields.io/badge/SharePoint%20Server%202019-Incompatible-red.svg "SharePoint Server 2019 requires SPFx 1.4.1 or lower")
![Does not work with SharePoint 2016 (Feature Pack 2)](https://img.shields.io/badge/SharePoint%20Server%202016%20(Feature%20Pack%202)-Incompatible-red.svg "SharePoint Server 2016 Feature Pack 2 requires SPFx 1.1")
![Local Workbench Unsupported](https://img.shields.io/badge/Local%20Workbench-Unsupported-red.svg "Local workbench is no longer available as of SPFx 1.13 and above")
![Hosted Workbench Compatible](https://img.shields.io/badge/Hosted%20Workbench-Compatible-green.svg)
![Compatible with Remote Containers](https://img.shields.io/badge/Remote%20Containers-Compatible-green.svg)
## Applies to
- [SharePoint Framework](https://aka.ms/spfx)
- [Microsoft 365 tenant](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant)
## Prerequisites
As this solution uses Microsoft Graph to manage data on user OneDrive it is required to approve all web api permission requests in SharePoint Admin page https://YourCoolTenantNameHere-admin.sharepoint.com/_layouts/15/online/AdminHome.aspx#/webApiPermissionManagement
## Solution
Solution|Author(s)
--------|---------
manage-data | [Adam Wójcik](https://github.com/Adam-it)
## Version history
Version|Date|Comments
-------|----|--------
1.0|Februaru 21, 2022|Initial release
## Minimal Path to Awesome
- Clone this repository (or [download this solution as a .ZIP file](https://pnp.github.io/download-partial/?url=https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-save-to-onedrive-app-personal-folder) then unzip it)
- Ensure that you are at the solution folder
- in the command-line run:
- `npm install`
- `gulp bundle --ship`
- `gulp package-solution --ship`
- Add to AppCatalog and deploy (check option to make this solution available to all sites)
- Approve the MS Graph API permissions in SharePoint Admin page
> This sample can also be opened with [VS Code Remote Development](https://code.visualstudio.com/docs/remote/remote-overview). Visit https://aka.ms/spfx-devcontainer for further instructions.
## Features
Description of the extension that expands upon high-level summary above.
This extension illustrates the following concepts:
- how to use Microsoft Graph api to use special approot on user OneDrive
- how to save/update data in a json file special approot folder on user OneDrive as a place to keep data a use in SharePoint or Teams
## References
- [Getting started with SharePoint Framework](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant)
- [Building for Microsoft teams](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/build-for-teams-overview)
- [Use Microsoft Graph in your solution](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/using-microsoft-graph-apis)
- [Publish SharePoint Framework applications to the Marketplace](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/publish-to-marketplace-overview)
- [Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) - Guidance, tooling, samples and open-source controls for your Microsoft 365 development
## Help
We do not support samples, but this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues.
If you're having issues building the solution, please run [spfx doctor](https://pnp.github.io/cli-microsoft365/cmd/spfx/spfx-doctor/) from within the solution folder to diagnose incompatibility issues with your environment.
You can try looking at [issues related to this sample](https://github.com/pnp/sp-dev-fx-webparts/issues?q=label%3A%22sample%3A%20react-save-to-onedrive-app-personal-folder%22) to see if anybody else is having the same issues.
You can also try looking at [discussions related to this sample](https://github.com/pnp/sp-dev-fx-webparts/discussions?discussions_q=react-save-to-onedrive-app-personal-folder) and see what the community is saying.
If you encounter any issues while using this sample, [create a new issue](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected%2Csample%3A%20react-save-to-onedrive-app-personal-folder&template=bug-report.yml&sample=react-save-to-onedrive-app-personal-folder&authors=@Adam-it&title=react-save-to-onedrive-app-personal-folder%20-%20).
For questions regarding this sample, [create a new question](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Aquestion%2Csample%3A%20react-save-to-onedrive-app-personal-folder&template=question.yml&sample=react-save-to-onedrive-app-personal-folder&authors=@Adam-it&title=react-save-to-onedrive-app-personal-folder%20-%20).
Finally, if you have an idea for improvement, [make a suggestion](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Aenhancement%2Csample%3A%20react-save-to-onedrive-app-personal-folder&template=suggestion.yml&sample=react-save-to-onedrive-app-personal-folder&authors=@Adam-it&title=react-save-to-onedrive-app-personal-folder%20-%20).
## Disclaimer
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
<img src="https://pnptelemetry.azurewebsites.net/sp-dev-fx-webparts/samples/react-save-to-onedrive-app-personal-folder" />

View File

@ -0,0 +1,18 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"manage-data-library": {
"components": [
{
"entrypoint": "./lib/index.js",
"manifest": "./src/libraries/manageData/ManageDataLibrary.manifest.json"
}
]
}
},
"externals": {},
"localizedResources": {
"ManageDataLibraryStrings": "lib/libraries/manageData/loc/{locale}.js"
}
}

View File

@ -0,0 +1,7 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
"workingDir": "./release/assets/",
"account": "<!-- STORAGE ACCOUNT NAME -->",
"container": "manage-data",
"accessKey": "<!-- ACCESS KEY -->"
}

View File

@ -0,0 +1,38 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "manage-data-client-side-solution",
"id": "cc04d03e-418c-44fc-a125-9fb84d9e9b33",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"skipFeatureDeployment": true,
"isDomainIsolated": false,
"developer": {
"name": "",
"websiteUrl": "",
"privacyUrl": "",
"termsOfUseUrl": "",
"mpnId": "Undefined-1.14.0-beta.5"
},
"webApiPermissionRequests": [
{
"resource": "Microsoft Graph",
"scope": "Sites.ReadWrite.All"
}
],
"metadata": {
"shortDescription": {
"default": "manage-data description"
},
"longDescription": {
"default": "manage-data description"
},
"screenshotPaths": [],
"videoUrl": "",
"categories": []
}
},
"paths": {
"zippedPackage": "solution/manage-data.sppkg"
}
}

View File

@ -0,0 +1,5 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
"port": 4321,
"https": true
}

View File

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

View File

@ -0,0 +1,16 @@
'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.`);
var getTasks = build.rig.getTasks;
build.rig.getTasks = function () {
var result = getTasks.call(build.rig);
result.set('serve', result.get('serve-deprecated'));
return result;
};
build.initialize(require('gulp'));

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,23 @@
{
"name": "manage-data",
"version": "0.0.1",
"private": false,
"main": "lib/index.js",
"scripts": {
"build": "gulp bundle",
"clean": "gulp clean",
"test": "gulp test"
},
"dependencies": {
"@microsoft/sp-webpart-base": "^1.14.0-beta.5"
},
"devDependencies": {
"@microsoft/sp-build-web": "1.14.0-beta.5",
"@microsoft/sp-tslint-rules": "1.14.0-beta.5",
"@microsoft/sp-module-interfaces": "1.14.0-beta.5",
"@microsoft/rush-stack-compiler-3.9": "0.4.47",
"gulp": "~4.0.2",
"ajv": "~5.2.2",
"@types/webpack-env": "1.13.1"
}
}

View File

@ -0,0 +1 @@
export { ManageDataLibrary } from './libraries/manageData/ManageDataLibrary';

View File

@ -0,0 +1,9 @@
{
"id": "a02d4028-02fe-451e-94e3-512872a414c9",
"alias": "ManageDataLibrary",
"componentType": "Library",
// The "*" signifies that the version should be taken from the package.json
"version": "*",
"manifestVersion": 2
}

View File

@ -0,0 +1,118 @@
import {
MSGraphClient,
HttpClient,
HttpClientResponse
} from '@microsoft/sp-http';
import IAppData from './model/IAppData';
export class ManageDataLibrary {
private static appDataFolderName: string = 'appData';
private static appDataFileName: string = 'savedData.json';
private mSGraphClient: MSGraphClient = null;
private httpClient: HttpClient = null;
constructor(
mSGraphClient: MSGraphClient,
httpClient: HttpClient) {
this.mSGraphClient = mSGraphClient;
this.httpClient = httpClient;
}
public async getData(): Promise<IAppData> {
return new Promise<IAppData>((resolve) =>
this.checkIfAppDataFolderExists()
.then(async folderExists => {
if (!folderExists) {
await this.createAppDataFolder();
}
this.mSGraphClient
.api(`/me/drive/special/approot:/${ManageDataLibrary.appDataFolderName}:/children?$filter=name eq '${ManageDataLibrary.appDataFileName}'`)
.version('v1.0')
.get((error, response: any, rawResponse?: any) => {
if (error) {
return;
}
if (response.value.length === 0) {
resolve(
{
data: null
} as IAppData);
}
const downloadUrl = response.value.filter(item => item.name === ManageDataLibrary.appDataFileName)[0]['@microsoft.graph.downloadUrl'];
this.httpClient
.get(downloadUrl, HttpClient.configurations.v1)
.then((innerResponse: HttpClientResponse): Promise<string> => {
if (innerResponse.ok) {
return innerResponse.text();
}
return Promise.reject(innerResponse.statusText);
})
.then((savedData: string) => {
const settings: IAppData = JSON.parse(savedData);
resolve(settings);
});
});
})
);
}
public saveData(appData: IAppData): Promise<any> {
return this.getAppDataFolder()
.then(response => {
const id = response.value.filter(item => item.name === ManageDataLibrary.appDataFolderName)[0].id;
const stream = JSON.stringify(appData);
this.mSGraphClient
.api(`/me/drive/items/${id}:/${ManageDataLibrary.appDataFileName}:/content`)
.version('v1.0')
.put(stream);
});
}
private async createAppDataFolder(): Promise<string> {
const driveItem = {
name: ManageDataLibrary.appDataFolderName,
folder: {},
'@microsoft.graph.conflictBehavior': 'fail'
};
return new Promise<string>((resolve, reject) =>
this.mSGraphClient
.api('/me/drive/special/approot/children')
.version('v1.0')
.post(driveItem)
.then(result => {
if (result != null) {
resolve(result.name.toString());
}
}));
}
private async checkIfAppDataFolderExists(): Promise<boolean> {
return new Promise<boolean>((resolve, reject) => {
resolve(this.getAppDataFolder().then(result => {
const isError = result.errorCode !== undefined;
return !isError ? result.value.some(item => item.name === ManageDataLibrary.appDataFolderName) : false;
}));
});
}
private async getAppDataFolder(): Promise<any> {
return new Promise<any>((resolve, reject) =>
this.mSGraphClient
.api(`/me/drive/special/approot/children?$filter=name eq '${ManageDataLibrary.appDataFolderName}'`)
.version('v1.0')
.get((error, response: any, rawResponse?: any) => {
if (error) {
resolve(error);
}
resolve(response);
}));
}
}

View File

@ -0,0 +1,3 @@
define([], function() {
return {}
});

View File

@ -0,0 +1,6 @@
declare interface IManageDataLibraryStrings {}
declare module 'ManageDataLibraryStrings' {
const strings: IManageDataLibraryStrings;
export = strings;
}

View File

@ -0,0 +1,3 @@
export default interface IAppData {
data: any;
}

View File

@ -0,0 +1,35 @@
{
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.9/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": [
"webpack-env"
],
"lib": [
"es5",
"dom",
"es2015.collection",
"es2015.promise"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx"
]
}

View File

@ -0,0 +1,29 @@
{
"extends": "./node_modules/@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-with-statement": true,
"semicolon": true,
"trailing-comma": false,
"typedef": false,
"typedef-whitespace": false,
"use-named-parameter": true,
"variable-name": false,
"whitespace": false
}
}

View File

@ -0,0 +1,33 @@
# Logs
logs
*.log
npm-debug.log*
# Dependency directories
node_modules
# Build generated files
dist
lib
release
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,16 @@
!dist
config
gulpfile.js
release
src
temp
tsconfig.json
tslint.json
*.log
.yo-rc.json
.vscode

View File

@ -0,0 +1,16 @@
{
"@microsoft/generator-sharepoint": {
"plusBeta": true,
"isCreatingSolution": true,
"version": "1.14.0-beta.5",
"libraryName": "client-webpart",
"libraryId": "68771efc-fba0-4f85-8592-c2f447e14c63",
"environment": "spo",
"packageManager": "npm",
"solutionName": "client-webpart",
"solutionShortDescription": "client-webpart description",
"skipFeatureDeployment": true,
"isDomainIsolated": false,
"componentType": "webpart"
}
}

View File

@ -0,0 +1,90 @@
# client-webpart
## Summary
This is a very simple Spfx webpart which presents how to use your own Spfx library in your solution. The webpart uses two methods from Spfx manage-data library to get and save data in user application's personal folder in OneDrive.
![image](../assets/in-sharepoint.png)
webpart added to sharepoint page
![image](../assets/in-teams.png)
webpart added to teams
## Compatibility
![SPFx 1.13.0](https://img.shields.io/badge/SPFx-1.13.0-green.svg)
![Node.js v14 | v12](https://img.shields.io/badge/Node.js-v14%20%7C%20v12-green.svg)
![Compatible with SharePoint Online](https://img.shields.io/badge/SharePoint%20Online-Compatible-green.svg)
![Does not work with SharePoint 2019](https://img.shields.io/badge/SharePoint%20Server%202019-Incompatible-red.svg "SharePoint Server 2019 requires SPFx 1.4.1 or lower")
![Does not work with SharePoint 2016 (Feature Pack 2)](https://img.shields.io/badge/SharePoint%20Server%202016%20(Feature%20Pack%202)-Incompatible-red.svg "SharePoint Server 2016 Feature Pack 2 requires SPFx 1.1")
![Local Workbench Unsupported](https://img.shields.io/badge/Local%20Workbench-Unsupported-red.svg "Local workbench is no longer available as of SPFx 1.13 and above")
![Hosted Workbench Compatible](https://img.shields.io/badge/Hosted%20Workbench-Compatible-green.svg)
![Compatible with Remote Containers](https://img.shields.io/badge/Remote%20Containers-Compatible-green.svg)
## Applies to
- [SharePoint Framework](https://aka.ms/spfx)
- [Microsoft 365 tenant](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant)
## Solution
Solution|Author(s)
--------|---------
client-webpart | [Adam Wójcik](https://github.com/Adam-it)
## Version history
Version|Date|Comments
-------|----|--------
1.0|Februaru 21, 2022|Initial release
## Minimal Path to Awesome
- Clone this repository (or [download this solution as a .ZIP file](https://pnp.github.io/download-partial/?url=https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-save-to-onedrive-app-personal-folder) then unzip it)
- Ensure that you are at the solution folder
- in the command-line run:
- `npm install`
- `gulp serve`
- `gulp bundle --ship`
- `gulp package-solution --ship`
- Add to AppCatalog and deploy
> This sample can also be opened with [VS Code Remote Development](https://code.visualstudio.com/docs/remote/remote-overview). Visit https://aka.ms/spfx-devcontainer for further instructions.
## Features
Description of the extension that expands upon high-level summary above.
This extension illustrates the following concepts:
- how to use Spfx library code in webpart
## References
- [Getting started with SharePoint Framework](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant)
- [Building for Microsoft teams](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/build-for-teams-overview)
- [Use Microsoft Graph in your solution](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/using-microsoft-graph-apis)
- [Publish SharePoint Framework applications to the Marketplace](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/publish-to-marketplace-overview)
- [Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) - Guidance, tooling, samples and open-source controls for your Microsoft 365 development
## Help
We do not support samples, but this community is always willing to help, and we want to improve these samples. We use GitHub to track issues, which makes it easy for community members to volunteer their time and help resolve issues.
If you're having issues building the solution, please run [spfx doctor](https://pnp.github.io/cli-microsoft365/cmd/spfx/spfx-doctor/) from within the solution folder to diagnose incompatibility issues with your environment.
You can try looking at [issues related to this sample](https://github.com/pnp/sp-dev-fx-webparts/issues?q=label%3A%22sample%3A%20react-save-to-onedrive-app-personal-folder%22) to see if anybody else is having the same issues.
You can also try looking at [discussions related to this sample](https://github.com/pnp/sp-dev-fx-webparts/discussions?discussions_q=react-save-to-onedrive-app-personal-folder) and see what the community is saying.
If you encounter any issues while using this sample, [create a new issue](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Abug-suspected%2Csample%3A%20react-save-to-onedrive-app-personal-folder&template=bug-report.yml&sample=react-save-to-onedrive-app-personal-folder&authors=@Adam-it&title=react-save-to-onedrive-app-personal-folder%20-%20).
For questions regarding this sample, [create a new question](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Aquestion%2Csample%3A%20react-save-to-onedrive-app-personal-folder&template=question.yml&sample=react-save-to-onedrive-app-personal-folder&authors=@Adam-it&title=react-save-to-onedrive-app-personal-folder%20-%20).
Finally, if you have an idea for improvement, [make a suggestion](https://github.com/pnp/sp-dev-fx-webparts/issues/new?assignees=&labels=Needs%3A+Triage+%3Amag%3A%2Ctype%3Aenhancement%2Csample%3A%20react-save-to-onedrive-app-personal-folder&template=suggestion.yml&sample=react-save-to-onedrive-app-personal-folder&authors=@Adam-it&title=react-save-to-onedrive-app-personal-folder%20-%20).
## Disclaimer
**THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.**
<img src="https://pnptelemetry.azurewebsites.net/sp-dev-fx-webparts/samples/react-save-to-onedrive-app-personal-folder" />

View File

@ -0,0 +1,18 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
"version": "2.0",
"bundles": {
"client-web-part": {
"components": [
{
"entrypoint": "./lib/webparts/client/ClientWebPart.js",
"manifest": "./src/webparts/client/ClientWebPart.manifest.json"
}
]
}
},
"externals": {},
"localizedResources": {
"ClientWebPartStrings": "lib/webparts/client/loc/{locale}.js"
}
}

View File

@ -0,0 +1,7 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
"workingDir": "./release/assets/",
"account": "<!-- STORAGE ACCOUNT NAME -->",
"container": "client-webpart",
"accessKey": "<!-- ACCESS KEY -->"
}

View File

@ -0,0 +1,40 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
"solution": {
"name": "client-webpart-client-side-solution",
"id": "68771efc-fba0-4f85-8592-c2f447e14c63",
"version": "1.0.0.0",
"includeClientSideAssets": true,
"skipFeatureDeployment": true,
"isDomainIsolated": false,
"developer": {
"name": "",
"websiteUrl": "",
"privacyUrl": "",
"termsOfUseUrl": "",
"mpnId": "Undefined-1.14.0-beta.5"
},
"metadata": {
"shortDescription": {
"default": "client-webpart description"
},
"longDescription": {
"default": "client-webpart description"
},
"screenshotPaths": [],
"videoUrl": "",
"categories": []
},
"features": [
{
"title": "client-webpart Feature",
"description": "The feature that activates elements of the client-webpart solution.",
"id": "9cadc74a-410a-43a5-ba7f-1bd8ae9e88ed",
"version": "1.0.0.0"
}
]
},
"paths": {
"zippedPackage": "solution/client-webpart.sppkg"
}
}

View File

@ -0,0 +1,6 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
"port": 4321,
"https": true,
"initialPage": "https://tenanttocheck.sharepoint.com/sites/hr-life/_layouts/workbench.aspx"
}

View File

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

View File

@ -0,0 +1,16 @@
'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.`);
var getTasks = build.rig.getTasks;
build.rig.getTasks = function () {
var result = getTasks.call(build.rig);
result.set('serve', result.get('serve-deprecated'));
return result;
};
build.initialize(require('gulp'));

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,33 @@
{
"name": "client-webpart",
"version": "0.0.1",
"private": true,
"main": "lib/index.js",
"scripts": {
"build": "gulp bundle",
"clean": "gulp clean",
"test": "gulp test"
},
"dependencies": {
"react": "16.13.1",
"react-dom": "16.13.1",
"office-ui-fabric-react": "7.174.1",
"manage-data": "0.0.1",
"@microsoft/sp-core-library": "1.14.0-beta.5",
"@microsoft/sp-property-pane": "1.14.0-beta.5",
"@microsoft/sp-webpart-base": "1.14.0-beta.5",
"@microsoft/sp-lodash-subset": "1.14.0-beta.5",
"@microsoft/sp-office-ui-fabric-core": "1.14.0-beta.5"
},
"devDependencies": {
"@types/react": "16.9.51",
"@types/react-dom": "16.9.8",
"@microsoft/sp-build-web": "1.14.0-beta.5",
"@microsoft/sp-tslint-rules": "1.14.0-beta.5",
"@microsoft/sp-module-interfaces": "1.14.0-beta.5",
"@microsoft/rush-stack-compiler-3.9": "0.4.47",
"gulp": "~4.0.2",
"ajv": "~5.2.2",
"@types/webpack-env": "1.13.1"
}
}

View File

@ -0,0 +1 @@
// A file is required to be in the root of the /src directory by the TypeScript compiler

View File

@ -0,0 +1,28 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "a6603137-966f-40c1-9897-4d2bb2250128",
"alias": "ClientWebPart",
"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", "TeamsPersonalApp", "TeamsTab", "SharePointFullPage"],
"supportsThemeVariants": true,
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
"group": { "default": "Other" },
"title": { "default": "Client" },
"description": { "default": "Client description" },
"officeFabricIconFontName": "Page",
"properties": {
"description": "Client"
}
}]
}

View File

@ -0,0 +1,98 @@
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 { IReadonlyTheme } from '@microsoft/sp-component-base';
import * as strings from 'ClientWebPartStrings';
import Client from './components/Client';
import { IClientProps } from './components/IClientProps';
export interface IClientWebPartProps {
description: string;
}
export default class ClientWebPart extends BaseClientSideWebPart<IClientWebPartProps> {
private _isDarkTheme: boolean = false;
private _environmentMessage: string = '';
protected onInit(): Promise<void> {
this._environmentMessage = this._getEnvironmentMessage();
return super.onInit();
}
public render(): void {
const element: React.ReactElement<IClientProps> = React.createElement(
Client,
{
description: this.properties.description,
isDarkTheme: this._isDarkTheme,
environmentMessage: this._environmentMessage,
hasTeamsContext: !!this.context.sdks.microsoftTeams,
userDisplayName: this.context.pageContext.user.displayName,
context: this.context
}
);
ReactDom.render(element, this.domElement);
}
private _getEnvironmentMessage(): string {
if (!!this.context.sdks.microsoftTeams) { // running in Teams
return this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentTeams : strings.AppTeamsTabEnvironment;
}
return this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentSharePoint : strings.AppSharePointEnvironment;
}
protected onThemeChanged(currentTheme: IReadonlyTheme | undefined): void {
if (!currentTheme) {
return;
}
this._isDarkTheme = !!currentTheme.isInverted;
const {
semanticColors
} = currentTheme;
this.domElement.style.setProperty('--bodyText', semanticColors.bodyText);
this.domElement.style.setProperty('--link', semanticColors.link);
this.domElement.style.setProperty('--linkHovered', semanticColors.linkHovered);
}
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
})
]
}
]
}
]
};
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,34 @@
@import '~office-ui-fabric-react/dist/sass/References.scss';
.client {
overflow: hidden;
padding: 1em;
color: "[theme:bodyText, default: #323130]";
color: var(--bodyText);
&.teams {
font-family: $ms-font-family-fallbacks;
}
}
.welcome {
text-align: center;
}
.welcomeImage {
width: 100%;
max-width: 420px;
}
.links {
a {
text-decoration: none;
color: "[theme:link, default:#03787c]";
color: var(--link); // note: CSS Custom Properties support is limited to modern browsers only
&:hover {
text-decoration: underline;
color: "[theme:linkHovered, default: #014446]";
color: var(--linkHovered); // note: CSS Custom Properties support is limited to modern browsers only
}
}
}

View File

@ -0,0 +1,74 @@
import { ActionButton } from 'office-ui-fabric-react/lib/Button';
import { TextField } from 'office-ui-fabric-react/lib/TextField';
import { MSGraphClient } from '@microsoft/sp-http';
import * as React from 'react';
import styles from './Client.module.scss';
import { IClientProps } from './IClientProps';
import * as ManageData from 'manage-data';
import { IClientState } from './IClientState';
export default class Client extends React.Component<IClientProps, IClientState> {
constructor(props) {
super(props);
this.state = {
manageDataLibrary: null,
savedData: ''
};
}
public componentDidMount(): void {
this.props.context.msGraphClientFactory
.getClient()
.then(async (client: MSGraphClient): Promise<void> => {
const manageDataLibrary = new ManageData.ManageDataLibrary(client, this.props.context.httpClient);
const savedData = await manageDataLibrary.getData();
this.setState({
manageDataLibrary,
savedData: savedData.data
});
});
}
public render(): React.ReactElement<IClientProps> {
const {
isDarkTheme,
environmentMessage,
hasTeamsContext,
} = this.props;
const { savedData } = this.state;
return (
<section className={`${styles.client} ${hasTeamsContext ? styles.teams : ''}`}>
<div className={styles.welcome}>
<img alt="" src={isDarkTheme ? require('../assets/welcome-dark.png') : require('../assets/welcome-light.png')} className={styles.welcomeImage} />
<div>{environmentMessage}</div>
</div>
<div>
<h3>Manage data in application personal folder in OneDrive</h3>
<TextField label="Data:" value={savedData} onChange={(e) => this.handleDocumentChange(e)} />
<ActionButton iconProps={{ iconName: 'Download' }} onClick={() => this.get()}>Get</ActionButton>
<ActionButton iconProps={{ iconName: 'Save' }} onClick={() => this.save()}>Save</ActionButton>
</div>
</section>
);
}
private get(): void {
this.state.manageDataLibrary.getData().then(result => this.setState({ savedData: result.data }));
}
private save(): void {
const dataToSave = this.state.savedData;
this.state.manageDataLibrary.saveData({ data: dataToSave }).then(response => {
this.get();
});
}
private handleDocumentChange(event): void {
const text: string = event.target.value;
this.setState({ savedData: text });
}
}

View File

@ -0,0 +1,10 @@
import { WebPartContext } from "@microsoft/sp-webpart-base";
export interface IClientProps {
description: string;
isDarkTheme: boolean;
environmentMessage: string;
hasTeamsContext: boolean;
userDisplayName: string;
context: WebPartContext;
}

View File

@ -0,0 +1,6 @@
import * as ManageData from 'manage-data';
export interface IClientState {
savedData: string;
manageDataLibrary: ManageData.ManageDataLibrary;
}

View File

@ -0,0 +1,11 @@
define([], function() {
return {
"PropertyPaneDescription": "Description",
"BasicGroupName": "Group Name",
"DescriptionFieldLabel": "Description Field",
"AppLocalEnvironmentSharePoint": "The app is running on your local environment as SharePoint web part",
"AppLocalEnvironmentTeams": "The app is running on your local environment as Microsoft Teams app",
"AppSharePointEnvironment": "The app is running on SharePoint page",
"AppTeamsTabEnvironment": "The app is running in Microsoft Teams"
}
});

View File

@ -0,0 +1,14 @@
declare interface IClientWebPartStrings {
PropertyPaneDescription: string;
BasicGroupName: string;
DescriptionFieldLabel: string;
AppLocalEnvironmentSharePoint: string;
AppLocalEnvironmentTeams: string;
AppSharePointEnvironment: string;
AppTeamsTabEnvironment: string;
}
declare module 'ClientWebPartStrings' {
const strings: IClientWebPartStrings;
export = strings;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,35 @@
{
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.9/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": [
"webpack-env"
],
"lib": [
"es5",
"dom",
"es2015.collection",
"es2015.promise"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx"
]
}

View File

@ -0,0 +1,29 @@
{
"extends": "./node_modules/@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-with-statement": true,
"semicolon": true,
"trailing-comma": false,
"typedef": false,
"typedef-whitespace": false,
"use-named-parameter": true,
"variable-name": false,
"whitespace": false
}
}