mirror of
https://github.com/pnp/sp-dev-fx-webparts.git
synced 2025-02-18 19:07:12 +00:00
Merge pull request #2206 from karamem0/react-my-approvals
Added react-my-approvals sample
This commit is contained in:
commit
846f7c9d52
33
samples/react-my-approvals/.gitignore
vendored
Normal file
33
samples/react-my-approvals/.gitignore
vendored
Normal 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
|
16
samples/react-my-approvals/.npmignore
Normal file
16
samples/react-my-approvals/.npmignore
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
!dist
|
||||||
|
config
|
||||||
|
|
||||||
|
gulpfile.js
|
||||||
|
|
||||||
|
release
|
||||||
|
src
|
||||||
|
temp
|
||||||
|
|
||||||
|
tsconfig.json
|
||||||
|
tslint.json
|
||||||
|
|
||||||
|
*.log
|
||||||
|
|
||||||
|
.yo-rc.json
|
||||||
|
.vscode
|
13
samples/react-my-approvals/.yo-rc.json
Normal file
13
samples/react-my-approvals/.yo-rc.json
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"@microsoft/generator-sharepoint": {
|
||||||
|
"plusBeta": false,
|
||||||
|
"isCreatingSolution": true,
|
||||||
|
"environment": "spo",
|
||||||
|
"version": "1.13.1",
|
||||||
|
"libraryName": "react-my-approvals",
|
||||||
|
"libraryId": "35ebc939-0c57-456f-9fea-bc8f2bae3e58",
|
||||||
|
"packageManager": "npm",
|
||||||
|
"isDomainIsolated": false,
|
||||||
|
"componentType": "webpart"
|
||||||
|
}
|
||||||
|
}
|
63
samples/react-my-approvals/README.md
Normal file
63
samples/react-my-approvals/README.md
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
# My Approvals
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
This web part demonstrates displaying the list of approval requests of Power Automate. Power Automate provides a new workflow feature that replaces SharePoint workflows, but it is a Power Platform feature, not a Microsoft 365 feature. You can display approval requests from only Power Automate site. This web part enable to display approval requests from SharePoint site.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|

|
||||||
|
-Incompatible-red.svg "SharePoint Server 2016 Feature Pack 2 requires SPFx 1.1")
|
||||||
|

|
||||||
|

|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
This web part uses *Microsoft Flow Service* API. You need to approve the API request after deploying the package.
|
||||||
|
|
||||||
|
- Approvals.Read.All
|
||||||
|
- Flows.Read.All
|
||||||
|
|
||||||
|
For more information, see [docs](https://docs.microsoft.com/ja-jp/sharepoint/dev/spfx/use-aadhttpclient).
|
||||||
|
|
||||||
|
## Solution
|
||||||
|
|
||||||
|
Solution|Author(s)
|
||||||
|
--------|---------
|
||||||
|
react-my-approvals|[Takashi Shinohara](https://github.com/karamem0) ([@karamem0](https://twitter.com/karamem0))
|
||||||
|
|
||||||
|
## Version history
|
||||||
|
|
||||||
|
Version|Date|Comments
|
||||||
|
-------|----|--------
|
||||||
|
1.0|January 11, 2022|Initial release
|
||||||
|
|
||||||
|
## 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-my-approvals%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-my-approvals) 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-my-approvals&template=bug-report.yml&sample=react-my-approvals&authors=@karamem0&title=react-my-approvals%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-my-approvals&template=question.yml&sample=react-my-approvals&authors=@karamem0&title=react-my-approvals%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-my-approvals&template=suggestion.yml&sample=react-my-approvals&authors=@karamem0&title=react-my-approvals%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-my-approvals" />
|
BIN
samples/react-my-approvals/assets/react-my-approvals.gif
Normal file
BIN
samples/react-my-approvals/assets/react-my-approvals.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 9.2 MiB |
49
samples/react-my-approvals/assets/sample.json
Normal file
49
samples/react-my-approvals/assets/sample.json
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "pnp-sp-dev-spfx-web-parts-react-my-approvals",
|
||||||
|
"source": "pnp",
|
||||||
|
"title": "My Approvals",
|
||||||
|
"shortDescription": "This web part demonstrates displaying the list of approval requests of Power Automate. Power Automate provides a new workflow feature that replaces SharePoint workflows, but it is a Power Platform feature, not a Microsoft 365 feature. You can display approval requests from only Power Automate site. This web part enable to display approval requests from SharePoint site.",
|
||||||
|
"url": "https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-my-approvals",
|
||||||
|
"longDescription": [
|
||||||
|
"This web part demonstrates displaying the list of approval requests of Power Automate. Power Automate provides a new workflow feature that replaces SharePoint workflows, but it is a Power Platform feature, not a Microsoft 365 feature. You can display approval requests from only Power Automate site. This web part enable to display approval requests from SharePoint site."
|
||||||
|
],
|
||||||
|
"creationDateTime": "2022-01-11",
|
||||||
|
"updateDateTime": "2022-01-11",
|
||||||
|
"products": [
|
||||||
|
"SharePoint"
|
||||||
|
],
|
||||||
|
"metadata": [
|
||||||
|
{
|
||||||
|
"key": "CLIENT-SIDE-DEV",
|
||||||
|
"value": "React"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "SPFX-VERSION",
|
||||||
|
"value": "1.13.0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thumbnails": [
|
||||||
|
{
|
||||||
|
"type": "image",
|
||||||
|
"order": 100,
|
||||||
|
"url": "https://github.com/pnp/sp-dev-fx-webparts/raw/main/samples/react-my-approvals/assets/react-my-approvals.gif",
|
||||||
|
"alt": "Web Part Preview"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"gitHubAccount": "karamem0",
|
||||||
|
"pictureUrl": "https://github.com/karamem0.png",
|
||||||
|
"name": "Takashi Shinohara"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"name": "Build your first SharePoint client-side web part",
|
||||||
|
"description": "Client-side web parts are client-side components that run in the context of a SharePoint page. Client-side web parts can be deployed to SharePoint environments that support the SharePoint Framework. You can also use modern JavaScript web frameworks, tools, and libraries to build them.",
|
||||||
|
"url": "https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/build-a-hello-world-web-part"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
19
samples/react-my-approvals/config/config.json
Normal file
19
samples/react-my-approvals/config/config.json
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
|
||||||
|
"version": "2.0",
|
||||||
|
"bundles": {
|
||||||
|
"my-approvals-web-part": {
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"entrypoint": "./lib/webparts/myApprovals/MyApprovalsWebPart.js",
|
||||||
|
"manifest": "./src/webparts/myApprovals/MyApprovalsWebPart.manifest.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"externals": {},
|
||||||
|
"localizedResources": {
|
||||||
|
"MyApprovalsWebPartStrings": "lib/webparts/myApprovals/loc/{locale}.js",
|
||||||
|
"ControlStrings": "node_modules/@pnp/spfx-controls-react/lib/loc/{locale}.js"
|
||||||
|
}
|
||||||
|
}
|
@ -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": "react-my-approvals",
|
||||||
|
"accessKey": "<!-- ACCESS KEY -->"
|
||||||
|
}
|
31
samples/react-my-approvals/config/package-solution.json
Normal file
31
samples/react-my-approvals/config/package-solution.json
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
|
||||||
|
"solution": {
|
||||||
|
"name": "my-approvals",
|
||||||
|
"id": "35ebc939-0c57-456f-9fea-bc8f2bae3e58",
|
||||||
|
"version": "1.0.0.0",
|
||||||
|
"includeClientSideAssets": true,
|
||||||
|
"skipFeatureDeployment": true,
|
||||||
|
"isDomainIsolated": false,
|
||||||
|
"developer": {
|
||||||
|
"name": "",
|
||||||
|
"websiteUrl": "",
|
||||||
|
"privacyUrl": "",
|
||||||
|
"termsOfUseUrl": "",
|
||||||
|
"mpnId": ""
|
||||||
|
},
|
||||||
|
"webApiPermissionRequests": [
|
||||||
|
{
|
||||||
|
"resource": "Microsoft Flow Service",
|
||||||
|
"scope": "Approvals.Read.All"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resource": "Microsoft Flow Service",
|
||||||
|
"scope": "Flows.Read.All"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"paths": {
|
||||||
|
"zippedPackage": "solution/my-approvals.sppkg"
|
||||||
|
}
|
||||||
|
}
|
6
samples/react-my-approvals/config/serve.json
Normal file
6
samples/react-my-approvals/config/serve.json
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
|
||||||
|
"port": 4321,
|
||||||
|
"https": true,
|
||||||
|
"initialPage": "https://karamem0test02.sharepoint.com/_layouts/workbench.aspx"
|
||||||
|
}
|
4
samples/react-my-approvals/config/write-manifests.json
Normal file
4
samples/react-my-approvals/config/write-manifests.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/write-manifests.schema.json",
|
||||||
|
"cdnBasePath": "<!-- PATH TO CDN -->"
|
||||||
|
}
|
16
samples/react-my-approvals/gulpfile.js
vendored
Normal file
16
samples/react-my-approvals/gulpfile.js
vendored
Normal 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'));
|
52076
samples/react-my-approvals/package-lock.json
generated
Normal file
52076
samples/react-my-approvals/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
36
samples/react-my-approvals/package.json
Normal file
36
samples/react-my-approvals/package.json
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
{
|
||||||
|
"name": "react-my-approvals",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"private": true,
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "gulp bundle",
|
||||||
|
"clean": "gulp clean",
|
||||||
|
"test": "gulp test"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@microsoft/sp-core-library": "1.13.1",
|
||||||
|
"@microsoft/sp-lodash-subset": "1.13.1",
|
||||||
|
"@microsoft/sp-office-ui-fabric-core": "1.13.1",
|
||||||
|
"@microsoft/sp-property-pane": "1.13.1",
|
||||||
|
"@microsoft/sp-webpart-base": "1.13.1",
|
||||||
|
"@pnp/spfx-controls-react": "^3.5.0",
|
||||||
|
"office-ui-fabric-react": "7.174.1",
|
||||||
|
"react": "16.13.1",
|
||||||
|
"react-dom": "16.13.1",
|
||||||
|
"react-intl": "^5.24.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@microsoft/rush-stack-compiler-3.9": "0.4.47",
|
||||||
|
"@microsoft/sp-build-web": "1.13.1",
|
||||||
|
"@microsoft/sp-module-interfaces": "1.13.1",
|
||||||
|
"@microsoft/sp-tslint-rules": "1.13.1",
|
||||||
|
"@types/react": "16.9.51",
|
||||||
|
"@types/react-dom": "16.9.8",
|
||||||
|
"@types/webpack-env": "1.13.1",
|
||||||
|
"ajv": "~5.2.2",
|
||||||
|
"gulp": "~4.0.2",
|
||||||
|
"tslint-microsoft-contrib": "^6.2.0",
|
||||||
|
"typescript": "^4.5.4"
|
||||||
|
}
|
||||||
|
}
|
1
samples/react-my-approvals/src/index.ts
Normal file
1
samples/react-my-approvals/src/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
// A file is required to be in the root of the /src directory by the TypeScript compiler
|
@ -0,0 +1,35 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
|
||||||
|
"id": "81f02f38-8477-46e9-b216-2ab84a4f907f",
|
||||||
|
"alias": "MyApprovalsWebPart",
|
||||||
|
"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"
|
||||||
|
],
|
||||||
|
"supportsThemeVariants": true,
|
||||||
|
"preconfiguredEntries": [
|
||||||
|
{
|
||||||
|
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
|
||||||
|
"group": {
|
||||||
|
"default": "Other"
|
||||||
|
},
|
||||||
|
"title": {
|
||||||
|
"default": "MyApprovals"
|
||||||
|
},
|
||||||
|
"description": {
|
||||||
|
"default": "View approval requests for you."
|
||||||
|
},
|
||||||
|
"officeFabricIconFontName": "Page",
|
||||||
|
"properties": {
|
||||||
|
"environment": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,97 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import * as ReactDom from 'react-dom';
|
||||||
|
import { IntlProvider } from 'react-intl';
|
||||||
|
import { Version } from '@microsoft/sp-core-library';
|
||||||
|
import {
|
||||||
|
IPropertyPaneConfiguration,
|
||||||
|
IPropertyPaneDropdownProps,
|
||||||
|
IPropertyPaneField,
|
||||||
|
PropertyPaneDropdown
|
||||||
|
} from '@microsoft/sp-property-pane';
|
||||||
|
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
|
||||||
|
|
||||||
|
import * as strings from 'MyApprovalsWebPartStrings';
|
||||||
|
import MyApprovals from './components/MyApprovals';
|
||||||
|
import { IMyApprovalsProps } from './components/IMyApprovalsProps';
|
||||||
|
import HttpClientService from './services/HttpClientService';
|
||||||
|
|
||||||
|
export interface IMyApprovalsWebPartProps {
|
||||||
|
title: string;
|
||||||
|
environment: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class MyApprovalsWebPart extends BaseClientSideWebPart<IMyApprovalsWebPartProps> {
|
||||||
|
|
||||||
|
private httpService: HttpClientService;
|
||||||
|
private environmentPanelField: IPropertyPaneField<IPropertyPaneDropdownProps>;
|
||||||
|
|
||||||
|
public render(): void {
|
||||||
|
const element: React.ReactElement<IMyApprovalsProps> = React.createElement(
|
||||||
|
MyApprovals,
|
||||||
|
{
|
||||||
|
httpService: this.httpService,
|
||||||
|
displayMode: this.displayMode,
|
||||||
|
environment: this.properties.environment,
|
||||||
|
title: this.properties.title,
|
||||||
|
setTitle: (value: string) => {
|
||||||
|
this.properties.title = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
ReactDom.render(
|
||||||
|
<IntlProvider locale={navigator.languages[0].substring(0, 2)}>
|
||||||
|
{element}
|
||||||
|
</IntlProvider>,
|
||||||
|
this.domElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setTitle(value: string): void {
|
||||||
|
this.properties.title = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async onInit(): Promise<void> {
|
||||||
|
this.httpService = await HttpClientService.create(this.context);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onDispose(): void {
|
||||||
|
ReactDom.unmountComponentAtNode(this.domElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async onPropertyPaneConfigurationStart(): Promise<void> {
|
||||||
|
const environments = await this.httpService.getEnvironments();
|
||||||
|
this.environmentPanelField = PropertyPaneDropdown(
|
||||||
|
'environment',
|
||||||
|
{
|
||||||
|
label: strings.EnvironmentLabel,
|
||||||
|
options: environments.map((value) => ({
|
||||||
|
key: value.name,
|
||||||
|
text: value.name
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
this.context.propertyPane.refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected get dataVersion(): Version {
|
||||||
|
return Version.parse('1.0');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||||
|
return {
|
||||||
|
pages: [
|
||||||
|
{
|
||||||
|
header: {
|
||||||
|
description: strings.PropertyPaneDescription
|
||||||
|
},
|
||||||
|
groups: [
|
||||||
|
{
|
||||||
|
groupFields: [
|
||||||
|
this.environmentPanelField
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,10 @@
|
|||||||
|
import { DisplayMode } from '@microsoft/sp-core-library';
|
||||||
|
import HttpClientService from '../services/HttpClientService';
|
||||||
|
|
||||||
|
export interface IMyApprovalsProps {
|
||||||
|
httpService: HttpClientService;
|
||||||
|
displayMode: DisplayMode;
|
||||||
|
environment: string;
|
||||||
|
title: string;
|
||||||
|
setTitle: (value: string) => void;
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
import { DisplayMode } from '@microsoft/sp-core-library';
|
||||||
|
import HttpClientService from '../services/HttpClientService';
|
||||||
|
|
||||||
|
export interface IMyApprovalsState {
|
||||||
|
name: string;
|
||||||
|
title: string;
|
||||||
|
requestDate: string;
|
||||||
|
requestUser: string;
|
||||||
|
}
|
@ -0,0 +1,29 @@
|
|||||||
|
@import '~office-ui-fabric-react/dist/sass/References.scss';
|
||||||
|
|
||||||
|
.root {
|
||||||
|
width: 100%;
|
||||||
|
.container {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: auto 1fr;
|
||||||
|
grid-template-rows: auto;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 1rem;
|
||||||
|
.count {
|
||||||
|
display: flex;
|
||||||
|
align-items: baseline;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0.25rem;
|
||||||
|
}
|
||||||
|
.items {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.loading {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: auto;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,145 @@
|
|||||||
|
import * as React from 'react';
|
||||||
|
import { useIntl } from 'react-intl';
|
||||||
|
import styles from './MyApprovals.module.scss';
|
||||||
|
import {
|
||||||
|
DetailsList,
|
||||||
|
DetailsListLayoutMode,
|
||||||
|
Link,
|
||||||
|
MessageBar,
|
||||||
|
MessageBarType,
|
||||||
|
SelectionMode,
|
||||||
|
Spinner,
|
||||||
|
SpinnerSize,
|
||||||
|
Text
|
||||||
|
} from 'office-ui-fabric-react';
|
||||||
|
import { WebPartTitle } from '@pnp/spfx-controls-react';
|
||||||
|
|
||||||
|
import * as strings from 'MyApprovalsWebPartStrings';
|
||||||
|
import { IMyApprovalsProps } from './IMyApprovalsProps';
|
||||||
|
import { IMyApprovalsState } from './IMyApprovalsState';
|
||||||
|
|
||||||
|
const MyApprovals = ({
|
||||||
|
httpService,
|
||||||
|
displayMode,
|
||||||
|
environment,
|
||||||
|
title,
|
||||||
|
setTitle
|
||||||
|
}: IMyApprovalsProps) => {
|
||||||
|
|
||||||
|
const intl = useIntl();
|
||||||
|
const [approvals, setApprovals] = React.useState<IMyApprovalsState[]>();
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (!httpService) return;
|
||||||
|
if (!environment) return;
|
||||||
|
(async () => {
|
||||||
|
setApprovals(
|
||||||
|
await httpService
|
||||||
|
.getApprovals(environment)
|
||||||
|
.then(async (values) => await Promise.all(values.map(async (value) => ({
|
||||||
|
name: value.name,
|
||||||
|
title: value.properties.title,
|
||||||
|
requestDate: await httpService.convertUtcToLocal(value.properties.creationDate),
|
||||||
|
requestUser: value.properties.principals.filter((item) => item.id === value.properties.owner.id)[0].displayName,
|
||||||
|
}))))
|
||||||
|
);
|
||||||
|
})();
|
||||||
|
}, [
|
||||||
|
httpService,
|
||||||
|
environment
|
||||||
|
]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={styles.root}>
|
||||||
|
{
|
||||||
|
environment
|
||||||
|
? (
|
||||||
|
<React.Fragment>
|
||||||
|
<WebPartTitle
|
||||||
|
displayMode={displayMode}
|
||||||
|
title={title}
|
||||||
|
updateProperty={setTitle} />
|
||||||
|
{
|
||||||
|
approvals
|
||||||
|
? (
|
||||||
|
<div className={styles.container}>
|
||||||
|
<div className={styles.count}>
|
||||||
|
<Text variant='mega'>
|
||||||
|
{approvals.length}
|
||||||
|
</Text>
|
||||||
|
<Text variant='medium'>
|
||||||
|
{strings.ApprovalItemsLabel}
|
||||||
|
</Text>
|
||||||
|
</div>
|
||||||
|
<div className={styles.items}>
|
||||||
|
<DetailsList
|
||||||
|
columns={[
|
||||||
|
{
|
||||||
|
key: 'title',
|
||||||
|
name: strings.ApprovalRequestTitleLabel,
|
||||||
|
fieldName: 'title',
|
||||||
|
data: 'string',
|
||||||
|
minWidth: 160,
|
||||||
|
isResizable: true,
|
||||||
|
onRender: (value) => (
|
||||||
|
<Link
|
||||||
|
href={`https://flow.microsoft.com/manage/environments/${environment}/approvals/received/${value.name}`}
|
||||||
|
target='_blank'>
|
||||||
|
{value.title}
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'requestDate',
|
||||||
|
name: strings.ApprovalRequestDateLabel,
|
||||||
|
fieldName: 'requestDate',
|
||||||
|
data: 'string',
|
||||||
|
minWidth: 160,
|
||||||
|
isResizable: true,
|
||||||
|
onRender: (value) =>
|
||||||
|
intl.formatDate(
|
||||||
|
value.requestDate.replace(/([+-]\d{2}:\d{2}|Z)$/, ""),
|
||||||
|
{
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'numeric',
|
||||||
|
day: 'numeric',
|
||||||
|
hour: 'numeric',
|
||||||
|
minute: 'numeric'
|
||||||
|
}
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'requestUser',
|
||||||
|
name: strings.ApprovalRequestUserLabel,
|
||||||
|
fieldName: 'requestUser',
|
||||||
|
data: 'string',
|
||||||
|
minWidth: 160,
|
||||||
|
isResizable: true
|
||||||
|
}
|
||||||
|
]}
|
||||||
|
items={approvals}
|
||||||
|
layoutMode={DetailsListLayoutMode.justified}
|
||||||
|
selectionMode={SelectionMode.none} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
<div className={styles.loading}>
|
||||||
|
<Spinner size={SpinnerSize.medium} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</React.Fragment>
|
||||||
|
)
|
||||||
|
: (
|
||||||
|
<MessageBar messageBarType={MessageBarType.error}>
|
||||||
|
{strings.EnvironmentEmptyError}
|
||||||
|
</MessageBar>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MyApprovals;
|
11
samples/react-my-approvals/src/webparts/myApprovals/loc/en-us.js
vendored
Normal file
11
samples/react-my-approvals/src/webparts/myApprovals/loc/en-us.js
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
define([], function () {
|
||||||
|
return {
|
||||||
|
"PropertyPaneDescription": "View approval requests for you.",
|
||||||
|
"EnvironmentLabel": "Environment",
|
||||||
|
"EnvironmentEmptyError": "The environment is not selected. Please edit the web part and select the environment.",
|
||||||
|
"ApprovalItemsLabel": "item(s)",
|
||||||
|
"ApprovalRequestTitleLabel": "Title",
|
||||||
|
"ApprovalRequestDateLabel": "Requested date",
|
||||||
|
"ApprovalRequestUserLabel": "Requested user"
|
||||||
|
}
|
||||||
|
});
|
11
samples/react-my-approvals/src/webparts/myApprovals/loc/ja-jp.js
vendored
Normal file
11
samples/react-my-approvals/src/webparts/myApprovals/loc/ja-jp.js
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
define([], function () {
|
||||||
|
return {
|
||||||
|
"PropertyPaneDescription": "承認リクエストを表示します。",
|
||||||
|
"EnvironmentLabel": "環境",
|
||||||
|
"EnvironmentEmptyError": "環境が選択されていません。Web パーツを編集して環境を選択してください。",
|
||||||
|
"ApprovalItemsLabel": "アイテム",
|
||||||
|
"ApprovalRequestTitleLabel": "タイトル",
|
||||||
|
"ApprovalRequestDateLabel": "依頼日時",
|
||||||
|
"ApprovalRequestUserLabel": "依頼者"
|
||||||
|
}
|
||||||
|
});
|
14
samples/react-my-approvals/src/webparts/myApprovals/loc/mystrings.d.ts
vendored
Normal file
14
samples/react-my-approvals/src/webparts/myApprovals/loc/mystrings.d.ts
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
declare interface IMyApprovalsWebPartStrings {
|
||||||
|
PropertyPaneDescription: string;
|
||||||
|
EnvironmentLabel: string;
|
||||||
|
EnvironmentEmptyError: string;
|
||||||
|
ApprovalItemsLabel: string;
|
||||||
|
ApprovalRequestTitleLabel: string;
|
||||||
|
ApprovalRequestDateLabel: string;
|
||||||
|
ApprovalRequestUserLabel: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'MyApprovalsWebPartStrings' {
|
||||||
|
const strings: IMyApprovalsWebPartStrings;
|
||||||
|
export = strings;
|
||||||
|
}
|
@ -0,0 +1,77 @@
|
|||||||
|
import { WebPartContext } from '@microsoft/sp-webpart-base';
|
||||||
|
import { AadHttpClient, SPHttpClient } from '@microsoft/sp-http';
|
||||||
|
|
||||||
|
interface IEnvironment {
|
||||||
|
name: string;
|
||||||
|
location: string;
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
properties: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IApproval {
|
||||||
|
name: string;
|
||||||
|
type: string;
|
||||||
|
id: string;
|
||||||
|
properties: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class HttpClientService {
|
||||||
|
|
||||||
|
private static readonly flowEndpoint: string = 'https://service.flow.microsoft.com';
|
||||||
|
|
||||||
|
public static async create(context: WebPartContext): Promise<HttpClientService> {
|
||||||
|
return new HttpClientService(
|
||||||
|
await context.aadHttpClientFactory.getClient(HttpClientService.flowEndpoint),
|
||||||
|
context.spHttpClient,
|
||||||
|
context.pageContext.web.absoluteUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
private flowHttpClient: AadHttpClient;
|
||||||
|
private spHttpClient: SPHttpClient;
|
||||||
|
private spBaseUrl: string;
|
||||||
|
|
||||||
|
private constructor(flowHttpClient: AadHttpClient, spHttpClient: SPHttpClient, spBaseUrl: string) {
|
||||||
|
this.flowHttpClient = flowHttpClient;
|
||||||
|
this.spHttpClient = spHttpClient;
|
||||||
|
this.spBaseUrl = spBaseUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getEnvironments(): Promise<IEnvironment[]> {
|
||||||
|
const response = await this.flowHttpClient.get(
|
||||||
|
'https://api.flow.microsoft.com/providers/Microsoft.ProcessSimple/environments' +
|
||||||
|
'?api-version=2016-11-01',
|
||||||
|
AadHttpClient.configurations.v1);
|
||||||
|
const json = await response.json();
|
||||||
|
if (json.error) {
|
||||||
|
throw new Error(json.error);
|
||||||
|
}
|
||||||
|
return json.value as IEnvironment[];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getApprovals(environments: string): Promise<IApproval[]> {
|
||||||
|
const response = await this.flowHttpClient.get(
|
||||||
|
`https://api.flow.microsoft.com/providers/Microsoft.ProcessSimple/environments/${environments}/approvalViews` +
|
||||||
|
'?$filter=properties/userRole eq \'Approver\' and properties/isActive eq \'true\' and properties/isDescending eq \'true\'' +
|
||||||
|
'&api-version=2016-11-01',
|
||||||
|
AadHttpClient.configurations.v1);
|
||||||
|
const json = await response.json();
|
||||||
|
if (json.error) {
|
||||||
|
throw new Error(json.error);
|
||||||
|
}
|
||||||
|
return json.value as IEnvironment[];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async convertUtcToLocal(date: string): Promise<string> {
|
||||||
|
const response = await this.spHttpClient.get(
|
||||||
|
`${this.spBaseUrl}/_api/web/RegionalSettings/TimeZone/utcToLocalTime(@date)?@date='${date}'`,
|
||||||
|
SPHttpClient.configurations.v1
|
||||||
|
);
|
||||||
|
const json = await response.json();
|
||||||
|
if (json.error) {
|
||||||
|
throw new Error(json.error);
|
||||||
|
}
|
||||||
|
return json.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 10 KiB |
Binary file not shown.
After Width: | Height: | Size: 542 B |
35
samples/react-my-approvals/tsconfig.json
Normal file
35
samples/react-my-approvals/tsconfig.json
Normal 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"
|
||||||
|
]
|
||||||
|
}
|
29
samples/react-my-approvals/tslint.json
Normal file
29
samples/react-my-approvals/tslint.json
Normal 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
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user