Merge pull request #1853 from ReactIntern/react-groups-teams
This commit is contained in:
commit
4945d129df
|
@ -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,12 @@
|
||||||
|
{
|
||||||
|
"@microsoft/generator-sharepoint": {
|
||||||
|
"isCreatingSolution": true,
|
||||||
|
"environment": "spo",
|
||||||
|
"version": "1.9.1",
|
||||||
|
"libraryName": "react-groups",
|
||||||
|
"libraryId": "e562b13d-7e90-4a1e-810c-ccde0ff27866",
|
||||||
|
"packageManager": "npm",
|
||||||
|
"isDomainIsolated": false,
|
||||||
|
"componentType": "webpart"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,112 @@
|
||||||
|
## All Microsoft 365 Groups and Teams with SPFx
|
||||||
|
|
||||||
|
### Summary
|
||||||
|
Web part pulls all Microsoft 365 Groups and Teams that the logged in user has access to view.
|
||||||
|
1. The Microsoft Groups view has filter option for private or public groups and can switch between viewing all groups or just my groups.
|
||||||
|
- Group Name (hover for group description)
|
||||||
|
- Link to email
|
||||||
|
- Link to SharePoint site
|
||||||
|
- Link to calendar
|
||||||
|
- Link to Planner plan (if available)
|
||||||
|
- Group privacy
|
||||||
|
2. The Microsoft Teams view has filter option for private or public Teams.
|
||||||
|
- Team Name (hover for group description)
|
||||||
|
- Link to email
|
||||||
|
- Link to SharePoint site
|
||||||
|
- Link to calendar
|
||||||
|
- Link to Planner plan (if available)
|
||||||
|
- Link to Team
|
||||||
|
- Team privacy
|
||||||
|
Each Team o Uses SharePoint theme.
|
||||||
|
|
||||||
|
![picture of the web part in action](./assets/Groups-in-my-organization.png)
|
||||||
|
![picture of the web part in action](./assets/My-Teams-Teams-Side-By-Side-Theme.png)
|
||||||
|
![picture of the web part in action](./assets/My-Groups-Public-Filter.png)
|
||||||
|
![picture of the web part in action](./assets/My-Teams-Teams-With-Tooltip.png)
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
![SPFx 1.10](https://img.shields.io/badge/SPFx-1.10.0-green.svg)
|
||||||
|
![Node.js LTS 8.x | LTS 10.x](https://img.shields.io/badge/Node.js-LTS%208.x%20%7C%20LTS%210.x-green.svg)
|
||||||
|
![SharePoint Online](https://img.shields.io/badge/SharePoint-Online-yellow.svg)
|
||||||
|
![Teams N/A: Untested with Microsoft Teams](https://img.shields.io/badge/Teams-N%2FA-lightgrey.svg "Untested with Microsoft Teams")
|
||||||
|
![Workbench Hosted: Only after API permissions granted](https://img.shields.io/badge/Workbench-Hosted-yellow.svg "Only after API permissions granted")
|
||||||
|
|
||||||
|
## Applies to
|
||||||
|
|
||||||
|
* [SharePoint Framework Developer Preview](https://docs.microsoft.com/sharepoint/dev/spfx/sharepoint-framework-overview)
|
||||||
|
* [SharePoint Framework](https://docs.microsoft.com/sharepoint/dev/spfx/sharepoint-framework-overview)
|
||||||
|
|
||||||
|
## Solution
|
||||||
|
|
||||||
|
Solution|Author(s)
|
||||||
|
--------|---------
|
||||||
|
React-Groups-Teams | [Alison Collins](https://github.com/ReactIntern) |
|
||||||
|
|
||||||
|
## Version history
|
||||||
|
|
||||||
|
| Version | Date | Comments |
|
||||||
|
| ------- | ---------------- | --------------- |
|
||||||
|
| 1.0.0 | April 16, 2021 | Initial release |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Prerequisites
|
||||||
|
|
||||||
|
- Administrative access to Azure AD of Microsoft 365 tenant
|
||||||
|
- SharePoint Online tenant
|
||||||
|
- You need following set of permissions in order to manage Microsoft 365 Groups and Teams
|
||||||
|
|
||||||
|
```
|
||||||
|
"webApiPermissionRequests": [{
|
||||||
|
"resource": "Microsoft Graph",
|
||||||
|
"scope": "Groups.Read.All"
|
||||||
|
}, {
|
||||||
|
"resource": "Team",
|
||||||
|
"scope": "Teams.ReadBasic.All"
|
||||||
|
}]
|
||||||
|
```
|
||||||
|
|
||||||
|
# Minimal Path to Awesome
|
||||||
|
|
||||||
|
- Clone this repo
|
||||||
|
- Navigate to the folder with current sample
|
||||||
|
- Restore dependencies: `$ npm i`
|
||||||
|
- Bundle the solution: `$ gulp bundle --ship`
|
||||||
|
- Package the solution: `$ gulp package-solution --ship`
|
||||||
|
- Upload to SharePoint tenant app catalog
|
||||||
|
- You will see a message saying that solution has pending permissions which need to be approved
|
||||||
|
- Approve the permission requests.
|
||||||
|
- Run `$ gulp serve --nobrowser`
|
||||||
|
- Open hosted workbench, i.e. `https://<tenant>.sharepoint.com/sites/<your site>/_layouts/15/workbench.aspx`
|
||||||
|
- Search and add `O365 Groups Manager` web part to see it in action
|
||||||
|
|
||||||
|
# Features
|
||||||
|
|
||||||
|
This project contains sample client-side web part built on the SharePoint Framework illustrating possibilities to quickly gain access to features in Microsoft 365 Groups and Teams using React and MS Graph.
|
||||||
|
|
||||||
|
This sample illustrates the following concepts on top of the SharePoint Framework:
|
||||||
|
|
||||||
|
- Explore MS Graph APIs for Microsoft 365 Group
|
||||||
|
- Using the MSGraphClient in a SharePoint Framework web part
|
||||||
|
- Requesting API permissions in a SharePoint Framework package
|
||||||
|
- Communicating with the Microsoft Graph using its REST API
|
||||||
|
- Using Office UI Fabric controls for building SharePoint Framework client-side web parts
|
||||||
|
- Passing web part properties to React components
|
||||||
|
|
||||||
|
# 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.**
|
||||||
|
|
||||||
|
## Support
|
||||||
|
|
||||||
|
We do not support samples, but we do use GitHub to track issues and constantly want to improve these samples.
|
||||||
|
|
||||||
|
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&template=bug-report.yml&sample=react-groups-teams&authors=@ReactIntern&title=react-groups-teams%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%3Abug-suspected&template=question.yml&sample=react-groups-teams&authors=@ReactIntern&title=react-groups-teams%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%3Abug-suspected&template=suggestion.yml&sample=react-groups-teams&authors=@ReactIntern&title=react-groups-teams%20-%20).
|
||||||
|
|
||||||
|
|
||||||
|
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-groups-teams" />
|
Binary file not shown.
After Width: | Height: | Size: 65 KiB |
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
Binary file not shown.
After Width: | Height: | Size: 120 KiB |
Binary file not shown.
After Width: | Height: | Size: 63 KiB |
|
@ -0,0 +1,68 @@
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "pnp-sp-dev-spfx-web-parts-react-groups-teams",
|
||||||
|
"source": "pnp",
|
||||||
|
"title": "All Microsoft 365 Groups and Teams",
|
||||||
|
"shortDescription": "Web part pulls all Microsoft 365 Groups and Teams that the logged in user has access to view.",
|
||||||
|
"url": "https://github.com/pnp/sp-dev-fx-webparts/tree/main/samples/react-groups-teams",
|
||||||
|
"longDescription": [
|
||||||
|
"Web part pulls all Microsoft 365 Groups and Teams that the logged in user has access to view."
|
||||||
|
],
|
||||||
|
"creationDateTime": "2021-05-06",
|
||||||
|
"updateDateTime": "2021-05-06",
|
||||||
|
"products": [
|
||||||
|
"SharePoint",
|
||||||
|
"Office"
|
||||||
|
],
|
||||||
|
"metadata": [
|
||||||
|
{
|
||||||
|
"key": "CLIENT-SIDE-DEV",
|
||||||
|
"value": "React"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "SPFX-VERSION",
|
||||||
|
"value": "1.10.0"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"thumbnails": [
|
||||||
|
{
|
||||||
|
"type": "image",
|
||||||
|
"order": 100,
|
||||||
|
"url": "https://github.com/pnp/sp-dev-fx-webparts/raw/main/samples/react-groups-teams/assets/Groups-in-my-organization.png",
|
||||||
|
"alt": "Web Part Preview"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "image",
|
||||||
|
"order": 101,
|
||||||
|
"url": "https://github.com/pnp/sp-dev-fx-webparts/raw/main/samples/react-groups-teams/assets/My-Groups-Public-Filter.png",
|
||||||
|
"alt": "Web Part Preview"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "image",
|
||||||
|
"order": 102,
|
||||||
|
"url": "https://github.com/pnp/sp-dev-fx-webparts/raw/main/samples/react-groups-teams/assets/My-Teams-Teams-Side-By-Side-Theme.png",
|
||||||
|
"alt": "Web Part Preview"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "image",
|
||||||
|
"order": 102,
|
||||||
|
"url": "https://github.com/pnp/sp-dev-fx-webparts/raw/main/samples/react-groups-teams/assets/My-Teams-Teams-With-Tooltip.png",
|
||||||
|
"alt": "Web Part Preview"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"gitHubAccount": "ReactIntern",
|
||||||
|
"pictureUrl": "https://github.com/ReactIntern.png",
|
||||||
|
"name": "Alison Collens"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
|
@ -0,0 +1,18 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
|
||||||
|
"version": "2.0",
|
||||||
|
"bundles": {
|
||||||
|
"microsoft-groups-web-part": {
|
||||||
|
"components": [
|
||||||
|
{
|
||||||
|
"entrypoint": "./lib/webparts/microsoftGroups/MicrosoftGroupsWebPart.js",
|
||||||
|
"manifest": "./src/webparts/microsoftGroups/MicrosoftGroupsWebPart.manifest.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"externals": {},
|
||||||
|
"localizedResources": {
|
||||||
|
"MicrosoftGroupsWebPartStrings": "lib/webparts/microsoftGroups/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-groups",
|
||||||
|
"accessKey": "<!-- ACCESS KEY -->"
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
|
||||||
|
"solution": {
|
||||||
|
"name": "react-groups-client-side-solution",
|
||||||
|
"id": "e562b13d-7e90-4a1e-810c-ccde0ff27866",
|
||||||
|
"version": "1.0.0.0",
|
||||||
|
"includeClientSideAssets": true,
|
||||||
|
"skipFeatureDeployment": true,
|
||||||
|
"isDomainIsolated": false,
|
||||||
|
"webApiPermissionRequests":[{
|
||||||
|
"resource": "Microsoft Graph",
|
||||||
|
"scope": "Groups.Read.All"
|
||||||
|
}, {
|
||||||
|
"resource": "Team",
|
||||||
|
"scope": "Teams.ReadBasic.All"
|
||||||
|
}]
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
"paths": {
|
||||||
|
"zippedPackage": "solution/react-groups.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 gulp = require('gulp');
|
||||||
|
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(gulp);
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,41 @@
|
||||||
|
{
|
||||||
|
"name": "react-groups",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"private": true,
|
||||||
|
"main": "lib/index.js",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"build": "gulp bundle",
|
||||||
|
"clean": "gulp clean",
|
||||||
|
"test": "gulp test"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@microsoft/sp-core-library": "1.9.1",
|
||||||
|
"@microsoft/sp-lodash-subset": "1.9.1",
|
||||||
|
"@microsoft/sp-office-ui-fabric-core": "1.9.1",
|
||||||
|
"@microsoft/sp-webpart-base": "1.9.1",
|
||||||
|
"@types/es6-promise": "0.0.33",
|
||||||
|
"@types/react": "16.8.8",
|
||||||
|
"@types/react-dom": "16.8.3",
|
||||||
|
"@types/webpack-env": "1.13.1",
|
||||||
|
"office-ui-fabric-react": "6.189.2",
|
||||||
|
"react": "16.8.5",
|
||||||
|
"react-dom": "16.8.5"
|
||||||
|
},
|
||||||
|
"resolutions": {
|
||||||
|
"@types/react": "16.8.8"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@microsoft/sp-build-web": "1.9.1",
|
||||||
|
"@microsoft/sp-tslint-rules": "1.9.1",
|
||||||
|
"@microsoft/sp-module-interfaces": "1.9.1",
|
||||||
|
"@microsoft/sp-webpart-workbench": "1.9.1",
|
||||||
|
"@microsoft/rush-stack-compiler-2.9": "0.7.16",
|
||||||
|
"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": "5ced32db-af85-469a-a3cb-39f3986e1f1a",
|
||||||
|
"alias": "MicrosoftGroupsWebPart",
|
||||||
|
"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": "Microsoft Groups" },
|
||||||
|
"description": { "default": "Microsoft Groups description" },
|
||||||
|
"officeFabricIconFontName": "Page",
|
||||||
|
"properties": {
|
||||||
|
"description": "Microsoft Groups"
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import * as ReactDom from 'react-dom';
|
||||||
|
import { Version } from '@microsoft/sp-core-library';
|
||||||
|
import {
|
||||||
|
BaseClientSideWebPart,
|
||||||
|
IPropertyPaneConfiguration,
|
||||||
|
PropertyPaneTextField
|
||||||
|
} from '@microsoft/sp-webpart-base';
|
||||||
|
|
||||||
|
import * as strings from 'MicrosoftGroupsWebPartStrings';
|
||||||
|
import MicrosoftGroups from './components/MicrosoftGroups';
|
||||||
|
|
||||||
|
export interface IMicrosoftGroupsWebPartProps {
|
||||||
|
description: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class MicrosoftGroupsWebPart extends BaseClientSideWebPart<IMicrosoftGroupsWebPartProps> {
|
||||||
|
|
||||||
|
public render(): void {
|
||||||
|
const element: React.ReactElement<IMicrosoftGroupsWebPartProps > = React.createElement(
|
||||||
|
MicrosoftGroups,
|
||||||
|
{
|
||||||
|
context: this.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,241 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import { MSGraphClient } from "@microsoft/sp-http";
|
||||||
|
import { WebPartContext } from '@microsoft/sp-webpart-base';
|
||||||
|
import styles from './MicrosoftGroups.module.scss';
|
||||||
|
import { Modal, TooltipHostBase } from 'office-ui-fabric-react';
|
||||||
|
import { Icon } from 'office-ui-fabric-react/lib/Icon';
|
||||||
|
import { iconClass } from './MyTeams';
|
||||||
|
|
||||||
|
export interface IGraphConsumerProps {
|
||||||
|
context: WebPartContext;
|
||||||
|
}
|
||||||
|
export interface IUserItem {
|
||||||
|
Topic: string;
|
||||||
|
DeliveryDate: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IGraphConsumerState {
|
||||||
|
AllGroupsresults: any;
|
||||||
|
MyGroupResults: any;
|
||||||
|
plannerId: string;
|
||||||
|
either: string;
|
||||||
|
Allgroupsdisplay: number;
|
||||||
|
mygroupsdisplay: number;
|
||||||
|
mode: string;
|
||||||
|
title: string;
|
||||||
|
isOpen: boolean;
|
||||||
|
MoreDetails: any;
|
||||||
|
Name: string;
|
||||||
|
Description: string;
|
||||||
|
TenantUrl: string;
|
||||||
|
MyGroupResultsFiltered: any;
|
||||||
|
AllGroupsresultsFiltered: any;
|
||||||
|
}
|
||||||
|
export default class MicrosoftGroups extends React.Component<IGraphConsumerProps, IGraphConsumerState> {
|
||||||
|
public _plannerIDs = [];
|
||||||
|
public _arr = [];
|
||||||
|
private graphClient: MSGraphClient = null;
|
||||||
|
public Tenant = this.props.context.pageContext.web.absoluteUrl.split('.')[0].split('//')[1];
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.GetPlanner = this.GetPlanner.bind(this);
|
||||||
|
this.GetGroups = this.GetGroups.bind(this);
|
||||||
|
this.state = {
|
||||||
|
AllGroupsresults: [],
|
||||||
|
MyGroupResults: [],
|
||||||
|
plannerId: '',
|
||||||
|
either: '',
|
||||||
|
Allgroupsdisplay: 0,
|
||||||
|
mygroupsdisplay: 0,
|
||||||
|
mode: 'All',
|
||||||
|
title: 'Groups In My Organization',
|
||||||
|
isOpen: false,
|
||||||
|
MoreDetails: [],
|
||||||
|
Name: '',
|
||||||
|
Description: '',
|
||||||
|
TenantUrl: '',
|
||||||
|
MyGroupResultsFiltered: [],
|
||||||
|
AllGroupsresultsFiltered: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public SwitchGroupList() {
|
||||||
|
if (this.state.title === 'Groups In My Organization') {
|
||||||
|
this.setState({ title: "My Groups" });
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.setState({ title: 'Groups In My Organization' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public SwitchGroupList2(Switch) {
|
||||||
|
if (Switch === 'All') {
|
||||||
|
this.setState({ AllGroupsresultsFiltered: this.state.AllGroupsresults });
|
||||||
|
this.setState({ MyGroupResultsFiltered: this.state.MyGroupResults });
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const SwitchedALL = this.state.AllGroupsresults.filter(item => item.Visibility === Switch);
|
||||||
|
this.setState({ AllGroupsresultsFiltered: SwitchedALL });
|
||||||
|
const SwitchedMY = this.state.MyGroupResults.filter(item => item.Visibility === Switch);
|
||||||
|
this.setState({ MyGroupResultsFiltered: SwitchedMY });
|
||||||
|
}
|
||||||
|
this.setState({ mode: Switch });
|
||||||
|
}
|
||||||
|
public OpenModal(GroupInfo) {
|
||||||
|
var array = [];
|
||||||
|
array.push(GroupInfo);
|
||||||
|
this.setState({ isOpen: true, MoreDetails: array, Name: GroupInfo.Name, Description: GroupInfo.Description });
|
||||||
|
}
|
||||||
|
public async GetPlanner() {
|
||||||
|
this.state.MyGroupResults.map(async GroupId => {
|
||||||
|
try {
|
||||||
|
this.graphClient = await this.props.context.msGraphClientFactory.getClient();
|
||||||
|
const results: any = await this.graphClient
|
||||||
|
.api(`/groups/${GroupId.Id}/planner/plans`)
|
||||||
|
.version('v1.0')
|
||||||
|
.get();
|
||||||
|
if (results.value.length > 0) {
|
||||||
|
var ID; results.value.map(Items => {
|
||||||
|
ID = Items.id;
|
||||||
|
});
|
||||||
|
var URL = `https://tasks.office.com/${this.Tenant}.com/EN-US/Home/Planner#/plantaskboard?groupId=${GroupId.Id}&planId=${ID}`;
|
||||||
|
var Planner = { Planner: URL };
|
||||||
|
var Results = Object.assign(GroupId, Planner);
|
||||||
|
GroupId = Results;
|
||||||
|
this.state.AllGroupsresults.map(Group => {
|
||||||
|
if (Group.Name === GroupId.Name) {
|
||||||
|
var Results2 = Object.assign(Group, Planner);
|
||||||
|
Group = Results2;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return this.setState({ MyGroupResultsFiltered: this.state.MyGroupResults });
|
||||||
|
} catch (error) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public GetGroups() {
|
||||||
|
var
|
||||||
|
GroupIDListAll = [],
|
||||||
|
GroupIDListMy = [],
|
||||||
|
myarray = [];
|
||||||
|
this.props.context.msGraphClientFactory
|
||||||
|
.getClient()
|
||||||
|
.then((client: MSGraphClient): void => {
|
||||||
|
client
|
||||||
|
.api(`me/transitiveMemberOf/microsoft.graph.group?$filter=groupTypes/any(a:a eq 'unified')`)
|
||||||
|
.version("v1.0")
|
||||||
|
.get((err, res) => {
|
||||||
|
if (err) {
|
||||||
|
}
|
||||||
|
if (res) {
|
||||||
|
res.value.map((item) => {
|
||||||
|
myarray.push({ Name: item.displayName, Id: item.id, Description: item.description, Mail: item.mail, Visibility: item.visibility });
|
||||||
|
GroupIDListMy.push({ Id: item.id });
|
||||||
|
|
||||||
|
});
|
||||||
|
this.setState({ MyGroupResultsFiltered: myarray, MyGroupResults: myarray });
|
||||||
|
this.GetPlanner();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.props.context.msGraphClientFactory
|
||||||
|
.getClient()
|
||||||
|
.then((client: MSGraphClient): void => {
|
||||||
|
client
|
||||||
|
.api(`groups?$filter=groupTypes/any(a:a eq 'unified')`)
|
||||||
|
.version("v1.0")
|
||||||
|
.get((err, res) => {
|
||||||
|
if (err) {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
if (res) {
|
||||||
|
res.value.map((item) => {
|
||||||
|
this._arr.push({ Name: item.displayName, Id: item.id, Description: item.description, Mail: item.mail, Visibility: item.visibility });
|
||||||
|
GroupIDListAll.push([item.id]);
|
||||||
|
|
||||||
|
});
|
||||||
|
this.setState({ AllGroupsresults: this._arr, AllGroupsresultsFiltered: this._arr });
|
||||||
|
this.GetPlanner();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
public componentDidMount() {
|
||||||
|
this.GetGroups();
|
||||||
|
}
|
||||||
|
public render(): React.ReactElement<IGraphConsumerProps> {
|
||||||
|
var Replaceregex = /\s+/g;
|
||||||
|
return <div className={styles.test}>
|
||||||
|
<div className={styles.tableCaptionStyle}>{this.state.title}
|
||||||
|
<div>
|
||||||
|
{this.state.mode === 'Public' ? <button className={styles.SelectedFilter} onClick={() => this.SwitchGroupList2('Public')}>Public</button> :
|
||||||
|
<button className={styles.Filters} onClick={() => this.SwitchGroupList2('Public')}>Public</button>}
|
||||||
|
|
||||||
|
{this.state.mode === 'All' ? <button className={styles.SelectedFilter} onClick={() => this.SwitchGroupList2('All')}>All</button> :
|
||||||
|
<button className={styles.Filters} onClick={() => this.SwitchGroupList2('All')}>All</button>}
|
||||||
|
|
||||||
|
{this.state.mode === 'Private' ? <button className={styles.SelectedFilter} onClick={() => this.SwitchGroupList2('Private')}>Private</button> :
|
||||||
|
<button className={styles.Filters} onClick={() => this.SwitchGroupList2('Private')}>Private</button>}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<button className={styles.SwitchGroups} onClick={() => this.SwitchGroupList()}> View {this.state.title === 'My Groups' ?
|
||||||
|
'Groups in my Organization' : 'My Groups'}</button>
|
||||||
|
</div>
|
||||||
|
<div className={styles.tableStyle}>
|
||||||
|
<div className={styles.headerStyle}>
|
||||||
|
<div className={styles.Center}>Group</div>
|
||||||
|
<div className={styles.Center}>Mail</div>
|
||||||
|
<div className={styles.Center}>Site</div>
|
||||||
|
<div className={styles.Center}>Calendar</div>
|
||||||
|
<div className={styles.Center}>Planner</div>
|
||||||
|
<div className={styles.Center} style={{ borderRight: 'none' }}>Visibility</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{this.state.title === 'My Groups' ? this.state.MyGroupResultsFiltered.map(Group => {
|
||||||
|
var GroupEmailSplit = Group.Mail.split("@");
|
||||||
|
Group.Mail = GroupEmailSplit[0];
|
||||||
|
return <div className={styles.rowStyle}>
|
||||||
|
<div className={styles.ToolTipName}>{Group.Name}<span className={styles.ToolTip}>{Group.Description}</span></div>
|
||||||
|
<a className={styles.Center} href={`https://outlook.office365.com/mail/group/${this.Tenant}.com/${Group.Mail.toLowerCase()}/email`}>
|
||||||
|
<Icon className={iconClass} style={{ color: '#087CD7' }} iconName="OutlookLogo"></Icon>
|
||||||
|
</a>
|
||||||
|
<a className={styles.Center} href={`https://${this.Tenant}.sharepoint.com/sites/${Group.Mail}`}>
|
||||||
|
<Icon className={iconClass} style={{ color: '#068B90' }} iconName="SharePointLogo"></Icon>
|
||||||
|
</a>
|
||||||
|
<a className={styles.Center} href={`https://outlook.office365.com/calendar/group/${this.Tenant}.com/${Group.Name.replace(Replaceregex, '')}/view/week`}>
|
||||||
|
<Icon className={iconClass} style={{ color: '#119AE2' }} iconName="Calendar"></Icon>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div className={styles.Center}>
|
||||||
|
{Group.Planner === undefined ? <div></div> : <a href={Group.Planner}>
|
||||||
|
<Icon className={iconClass} style={{ color: '#077D3F' }} iconName="ViewListTree"></Icon></a>}
|
||||||
|
</div>
|
||||||
|
<div className={styles.Center} style={{ borderRight: 'none' }}>{Group.Visibility}</div>
|
||||||
|
</div>;
|
||||||
|
}) : this.state.AllGroupsresultsFiltered.map(Group => {
|
||||||
|
var GroupEmailSplit = Group.Mail.split("@");
|
||||||
|
Group.Mail = GroupEmailSplit[0];
|
||||||
|
return <div className={styles.rowStyle}>
|
||||||
|
<div className={styles.ToolTipName}>{Group.Name}<span className={styles.ToolTip}>{Group.Description}</span></div>
|
||||||
|
<a className={styles.Center} href={`https://outlook.office365.com/mail/group/${this.Tenant}.com/${Group.Mail.toLowerCase()}/email`}>
|
||||||
|
<Icon className={iconClass} style={{ color: '#087CD7' }} iconName="OutlookLogo"></Icon>
|
||||||
|
</a>
|
||||||
|
<a className={styles.Center} href={`https://${this.Tenant}.sharepoint.com/sites/${Group.Mail}`}>
|
||||||
|
<Icon className={iconClass} style={{ color: '#068B90' }} iconName="SharePointLogo"></Icon>
|
||||||
|
</a>
|
||||||
|
<a className={styles.Center} href={`https://outlook.office365.com/calendar/group/${this.Tenant}.com/${Group.Name.replace(Replaceregex, '')}/view/week`}>
|
||||||
|
<Icon className={iconClass} style={{ color: '#119AE2' }} iconName="Calendar"></Icon>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div className={styles.Center}>
|
||||||
|
{Group.Planner === undefined ? <div></div> : <a href={Group.Planner}>
|
||||||
|
<Icon className={iconClass} style={{ color: '#077D3F' }} iconName="ViewListTree"></Icon></a>}
|
||||||
|
</div>
|
||||||
|
<div className={styles.Center} style={{ borderRight: 'none' }}>{Group.Visibility}</div>
|
||||||
|
</div>;
|
||||||
|
})}
|
||||||
|
</div>;
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,425 @@
|
||||||
|
@import '~office-ui-fabric-react/dist/sass/References.scss';
|
||||||
|
.test {
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.none {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
.Center {
|
||||||
|
padding-top: 10px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: center;
|
||||||
|
border-right: 2px solid white;
|
||||||
|
padding-right: 13px;
|
||||||
|
padding-left: 13px;
|
||||||
|
border-bottom: 2px solid white;
|
||||||
|
|
||||||
|
/*
|
||||||
|
position: relative;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: center;
|
||||||
|
border-right: 2px solid white;
|
||||||
|
padding: 8px 13px 8px;
|
||||||
|
border-bottom: 2px solid white;
|
||||||
|
max-width: 132px;
|
||||||
|
word-break: break-word;*/
|
||||||
|
}
|
||||||
|
.SwitchGroups{
|
||||||
|
position:absolute;
|
||||||
|
bottom:2px;
|
||||||
|
right:10px;
|
||||||
|
font-size:16px;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
cursor:pointer;
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
|
.SwitchGroups:hover{
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.headerStyle{
|
||||||
|
background-color: "[theme: themePrimary, default: #0078d7]";
|
||||||
|
display: table-row ;
|
||||||
|
border: solid ;
|
||||||
|
text-align : center ;
|
||||||
|
width : 100px ;
|
||||||
|
height : 30px ;
|
||||||
|
padding-top : 10px ;
|
||||||
|
color : white ;
|
||||||
|
}
|
||||||
|
.tableStyle{
|
||||||
|
display: table;
|
||||||
|
min-width: 100%;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
.panelStyle{
|
||||||
|
background: lightblue ;
|
||||||
|
}
|
||||||
|
.tableCaptionStyle{
|
||||||
|
background-color: "[theme: themePrimary, default: #0078d7]";
|
||||||
|
font-size: 20px ;
|
||||||
|
font-weight: bold ;
|
||||||
|
border: solid ;
|
||||||
|
text-align:center ;
|
||||||
|
height:79px;
|
||||||
|
padding-top:3px ;
|
||||||
|
border-radius:25px ;
|
||||||
|
color:white;
|
||||||
|
border-radius: 25px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-top: auto;
|
||||||
|
min-width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
position: relative;
|
||||||
|
font-weight:normal;
|
||||||
|
}
|
||||||
|
.rowStyle{
|
||||||
|
display : table-row ;
|
||||||
|
background: #eee ;
|
||||||
|
padding: 20px ;
|
||||||
|
margin: 20px ;
|
||||||
|
font-weight : bold ;
|
||||||
|
}
|
||||||
|
.row {
|
||||||
|
@include ms-Grid-row;
|
||||||
|
@include ms-fontColor-white;
|
||||||
|
background-color: $ms-color-themeDark;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.CellStyle{
|
||||||
|
display: table-cell ;
|
||||||
|
border: solid ;
|
||||||
|
border-color : white ;
|
||||||
|
text-align : center ;
|
||||||
|
min-width : 75px ;
|
||||||
|
height : 30px ;
|
||||||
|
width: fit-content;
|
||||||
|
padding-top : 10px ;
|
||||||
|
}
|
||||||
|
.buttons {
|
||||||
|
display: table-cell ;
|
||||||
|
|
||||||
|
text-align : center ;
|
||||||
|
width : 160px ;
|
||||||
|
height : 30px ;
|
||||||
|
padding-top : 10px ;
|
||||||
|
}
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// @import '~office-ui-fabric-react/dist/sass/References.scss';
|
||||||
|
.test {
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
.none {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
.CenterRight {
|
||||||
|
border-right:none;
|
||||||
|
padding: 5px 10px 3px;
|
||||||
|
margin-left: 26px;
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: center;
|
||||||
|
border-right: 2px solid white;
|
||||||
|
//border-bottom: 2px solid white;
|
||||||
|
max-width: 113px;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
.Center {
|
||||||
|
padding: 5px 10px 3px;
|
||||||
|
margin-left: 26px;
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: center;
|
||||||
|
border-right: 2px solid white;
|
||||||
|
border-bottom: 2px solid white;
|
||||||
|
max-width: 113px;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
.ToolTipName {
|
||||||
|
position: relative;
|
||||||
|
padding-bottom: 0px;
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: center;
|
||||||
|
border-right: 2px solid white;
|
||||||
|
padding: 8px 13px 8px;
|
||||||
|
border-bottom: 2px solid white;
|
||||||
|
max-width: 132px;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
.ToolTip {
|
||||||
|
visibility: hidden;
|
||||||
|
padding: 7px;
|
||||||
|
background-color: $ms-color-themeDark;
|
||||||
|
color: #fff;
|
||||||
|
text-align: center;
|
||||||
|
border-radius: 6px;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
bottom: 86%;
|
||||||
|
right: 0%;
|
||||||
|
left: 0%;
|
||||||
|
padding-left: 7px;
|
||||||
|
padding-right: 7px;
|
||||||
|
}
|
||||||
|
.ToolTipName:hover .ToolTip {
|
||||||
|
visibility: visible;
|
||||||
|
padding: 5px 0px 5px 0px;
|
||||||
|
background-color: "[theme: themeLight, default: #0078d7]";
|
||||||
|
}
|
||||||
|
.MainViewCenter {
|
||||||
|
width: 50%;
|
||||||
|
padding-top: 10px;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
display: table-cell;
|
||||||
|
vertical-align: middle;
|
||||||
|
text-align: center;
|
||||||
|
padding-right: 13px;
|
||||||
|
padding-left: 13px;
|
||||||
|
cursor:pointer;
|
||||||
|
background-color: "[theme: themeDark, default: #0078d7]";
|
||||||
|
border: none;
|
||||||
|
color: white;
|
||||||
|
border-right: 2px solid white;
|
||||||
|
|
||||||
|
}
|
||||||
|
.MainViewCenter :hover{
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.Filters {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: "[theme: themePrimary, default: #0078d7]";
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border: 2px solid;
|
||||||
|
border-color: "[theme: themeDark, default: #0078d7]";
|
||||||
|
margin-right: 4px;
|
||||||
|
margin-top: 9px;
|
||||||
|
}
|
||||||
|
.Filters:focus {
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
.SelectedFilter {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: "[theme: themeDark, default: #0078d7]";
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border: 2px solid;
|
||||||
|
border-color: "[theme: themeDark, default: #0078d7]";
|
||||||
|
margin-right: 4px;
|
||||||
|
margin-top: 9px;}
|
||||||
|
.SelectedFilter:focus{
|
||||||
|
outline:none;
|
||||||
|
}
|
||||||
|
.OneNoteIcon {
|
||||||
|
height: 32px;
|
||||||
|
width: 32px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.SwitchGroups{
|
||||||
|
position:absolute;
|
||||||
|
bottom:2px;
|
||||||
|
right:10px;
|
||||||
|
font-size:16px;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
cursor:pointer;
|
||||||
|
color:white;
|
||||||
|
}
|
||||||
|
.SwitchGroups:hover{
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.headerStyle{
|
||||||
|
background-color: "[theme: themeSecondary, default: #0078d7]"; //themeSecondary
|
||||||
|
display: table-row ;
|
||||||
|
border: solid ;
|
||||||
|
text-align : center ;
|
||||||
|
width : 100px ;
|
||||||
|
height : 30px ;
|
||||||
|
padding-top : 10px ;
|
||||||
|
color : white ;
|
||||||
|
}
|
||||||
|
.tableStyle{
|
||||||
|
display: table;
|
||||||
|
min-width: 100%;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
.panelStyle{
|
||||||
|
background: lightblue ;
|
||||||
|
}
|
||||||
|
.tableCaptionStyle{
|
||||||
|
background-color: "[theme: themePrimary, default: #0078d7]";
|
||||||
|
// display: block ;
|
||||||
|
font-size: 20px ;
|
||||||
|
font-weight: bold ;
|
||||||
|
border: solid ;
|
||||||
|
text-align:center ;
|
||||||
|
height:79px;
|
||||||
|
padding-top:3px ;
|
||||||
|
border-radius:25px ;
|
||||||
|
color:white;
|
||||||
|
border-radius: 25px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-top: auto;
|
||||||
|
min-width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
position: relative;
|
||||||
|
font-weight:normal;
|
||||||
|
}
|
||||||
|
.rowStyle{
|
||||||
|
display : table-row ;
|
||||||
|
background: #eee ;
|
||||||
|
padding: 20px ;
|
||||||
|
margin: 20px ;
|
||||||
|
font-weight : bold ;
|
||||||
|
}
|
||||||
|
.row {
|
||||||
|
@include ms-Grid-row;
|
||||||
|
@include ms-fontColor-white;
|
||||||
|
background-color: $ms-color-themeDark;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
.CellStyle{
|
||||||
|
display: table-cell ;
|
||||||
|
border: solid ;
|
||||||
|
border-color : white ;
|
||||||
|
text-align : center ;
|
||||||
|
min-width : 75px ;
|
||||||
|
height : 30px ;
|
||||||
|
width: fit-content;
|
||||||
|
padding-top : 10px ;
|
||||||
|
}
|
||||||
|
.buttons {
|
||||||
|
display: table-cell ;
|
||||||
|
|
||||||
|
text-align : center ;
|
||||||
|
width : 160px ;
|
||||||
|
height : 30px ;
|
||||||
|
padding-top : 10px ;
|
||||||
|
}
|
||||||
|
.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,36 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import { MSGraphClient } from "@microsoft/sp-http";
|
||||||
|
import { WebPartContext } from '@microsoft/sp-webpart-base';
|
||||||
|
import styles from './MicrosoftGroups.module.scss';
|
||||||
|
import TeamsGraphConsumer from './MyTeams';
|
||||||
|
import GraphConsumer from './Microsoft365Groups';
|
||||||
|
export interface IMicrosoftGroupsProps {
|
||||||
|
context: WebPartContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IMicrosoftGroupsState {
|
||||||
|
title: string;
|
||||||
|
}
|
||||||
|
export default class MicrosoftGroups extends React.Component<IMicrosoftGroupsProps, IMicrosoftGroupsState> {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
title: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public SwitchGroupList(ID) {
|
||||||
|
this.setState({title: ID});
|
||||||
|
}
|
||||||
|
|
||||||
|
public render(): React.ReactElement<IMicrosoftGroupsProps> {
|
||||||
|
return <div>
|
||||||
|
<div className={styles.tableStyle}>
|
||||||
|
<div className={styles.headerStyle} >
|
||||||
|
<button className={styles.MainViewCenter} id={'Microsoft 365 Groups'} onClick={() => this.SwitchGroupList('Microsoft 365 Groups')}>Microsoft 365 Groups</button>
|
||||||
|
<button className={styles.MainViewCenter} id={'My Teams'} onClick={() => this.SwitchGroupList('My Teams')}>My Teams</button>
|
||||||
|
</div></div>
|
||||||
|
{this.state.title === 'Microsoft 365 Groups' ? <GraphConsumer context={this.props.context}/> : <div></div>}
|
||||||
|
{this.state.title === 'My Teams' ? <TeamsGraphConsumer context={this.props.context} hidden={false}/>: <TeamsGraphConsumer context={this.props.context} hidden={true}/>}
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,200 @@
|
||||||
|
import * as React from 'react';
|
||||||
|
import { MSGraphClient } from "@microsoft/sp-http";
|
||||||
|
import { WebPartContext } from '@microsoft/sp-webpart-base';
|
||||||
|
import styles from './MicrosoftGroups.module.scss';
|
||||||
|
import { Icon } from 'office-ui-fabric-react/lib/Icon';
|
||||||
|
import { ActionButton } from 'office-ui-fabric-react/lib/Button';
|
||||||
|
import { mergeStyles } from 'office-ui-fabric-react/lib/Styling';
|
||||||
|
export const iconClass = mergeStyles({
|
||||||
|
fontSize: 32,
|
||||||
|
height: 32,
|
||||||
|
width: 32
|
||||||
|
});
|
||||||
|
export interface IMyTeamsProps {
|
||||||
|
context: WebPartContext;
|
||||||
|
hidden: Boolean;
|
||||||
|
}
|
||||||
|
export interface IUserItem {
|
||||||
|
Topic: string;
|
||||||
|
DeliveryDate: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IMyTeamsState {
|
||||||
|
MyGroupResults: any;
|
||||||
|
MyGroupsresultsFiltered: any;
|
||||||
|
plannerId: string;
|
||||||
|
Allgroupsdisplay: number;
|
||||||
|
mygroupsdisplay: number;
|
||||||
|
mode: string;
|
||||||
|
title: string;
|
||||||
|
TenantURL: String;
|
||||||
|
}
|
||||||
|
export default class MyTeams extends React.Component<IMyTeamsProps, IMyTeamsState> {
|
||||||
|
public Tenant = this.props.context.pageContext.web.absoluteUrl.split('.')[0].split('//')[1];
|
||||||
|
private graphClient: MSGraphClient = null;
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
MyGroupResults: [],
|
||||||
|
MyGroupsresultsFiltered: [],
|
||||||
|
plannerId: '',
|
||||||
|
Allgroupsdisplay: 0,
|
||||||
|
mygroupsdisplay: 0,
|
||||||
|
mode: 'All',
|
||||||
|
title: 'Teams in Microsoft Teams In My Organization',
|
||||||
|
TenantURL: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
public SwitchGroupList(Switch) {
|
||||||
|
if (Switch === 'All') {
|
||||||
|
this.setState({ MyGroupsresultsFiltered: this.state.MyGroupResults });
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const SwitchedMY = this.state.MyGroupResults.filter(item => item.Visibility === Switch);
|
||||||
|
this.setState({ MyGroupsresultsFiltered: SwitchedMY });
|
||||||
|
}
|
||||||
|
this.setState({ mode: Switch });
|
||||||
|
}
|
||||||
|
public async GetPlanner() {
|
||||||
|
this.state.MyGroupResults.map(async GroupId => {
|
||||||
|
try {
|
||||||
|
this.graphClient = await this.props.context.msGraphClientFactory.getClient();
|
||||||
|
const results: any = await this.graphClient
|
||||||
|
.api(`/groups/${GroupId.Id}/planner/plans`)
|
||||||
|
.version('v1.0')
|
||||||
|
.get();
|
||||||
|
if (results.value.length > 0) {
|
||||||
|
var ID; results.value.map(Items => {
|
||||||
|
ID = Items.id;
|
||||||
|
});
|
||||||
|
var URL = `https://tasks.office.com/${this.Tenant}.com/EN-US/Home/Planner#/plantaskboard?groupId=${GroupId.Id}&planId=${ID}`;
|
||||||
|
var Planner = { Planner: URL };
|
||||||
|
var Results = Object.assign(GroupId, Planner);
|
||||||
|
GroupId = Results;
|
||||||
|
}
|
||||||
|
return results.value;
|
||||||
|
} catch (error) {
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
public GetTeamsURL() {
|
||||||
|
this.state.MyGroupResults.map(Group => {
|
||||||
|
this.props.context.msGraphClientFactory
|
||||||
|
.getClient()
|
||||||
|
.then((client: MSGraphClient): void => {
|
||||||
|
client
|
||||||
|
.api(`/teams/${Group.Id}/?$select=webUrl`)
|
||||||
|
.version("v1.0")
|
||||||
|
.get((err, res) => {
|
||||||
|
if (err) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (res) {
|
||||||
|
var Results = Object.assign(Group, { WebUrl: res.webUrl });
|
||||||
|
Group = Results;
|
||||||
|
this.setState({ MyGroupsresultsFiltered: this.state.MyGroupResults });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public async GetMail() {
|
||||||
|
this.state.MyGroupResults.map(Group => {
|
||||||
|
this.props.context.msGraphClientFactory
|
||||||
|
.getClient()
|
||||||
|
.then((client: MSGraphClient): void => {
|
||||||
|
client
|
||||||
|
.api(`groups/${Group.Id}/`)
|
||||||
|
.version("v1.0")
|
||||||
|
.get((err, res) => {
|
||||||
|
if (err) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (res) {
|
||||||
|
var Results = Object.assign(Group, { Mail: res.mail });
|
||||||
|
Group = Results;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public componentDidMount() {
|
||||||
|
this.setState({ TenantURL: this.props.context.pageContext.web.absoluteUrl });
|
||||||
|
var array = [];
|
||||||
|
this.props.context.msGraphClientFactory
|
||||||
|
.getClient()
|
||||||
|
.then((client: MSGraphClient): void => {
|
||||||
|
client
|
||||||
|
.api(`me/joinedTeams`)
|
||||||
|
.version("v1.0")
|
||||||
|
.get((err, res) => {
|
||||||
|
if (err) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (res) {
|
||||||
|
res.value.map((item) => {
|
||||||
|
array.push({ Name: item.displayName, Id: item.id, Description: item.description, Visibility: item.visibility });
|
||||||
|
});
|
||||||
|
this.setState({ MyGroupResults: array });
|
||||||
|
this.GetMail();
|
||||||
|
this.GetPlanner();
|
||||||
|
this.GetTeamsURL();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public render(): React.ReactElement<IMyTeamsProps> {
|
||||||
|
var Replaceregex = /\s+/g;
|
||||||
|
return this.props.hidden ? <div></div> : <div className={styles.test}>
|
||||||
|
<div className={styles.tableCaptionStyle} style={{ borderRight: 'none' }}>My Teams Teams<div>
|
||||||
|
|
||||||
|
{this.state.mode === 'Public' ? <button className={styles.SelectedFilter} onClick={() => this.SwitchGroupList('Public')}>Public</button> :
|
||||||
|
<button className={styles.Filters} onClick={() => this.SwitchGroupList('Public')}>Public</button>}
|
||||||
|
|
||||||
|
{this.state.mode === 'All' ? <button className={styles.SelectedFilter} onClick={() => this.SwitchGroupList('All')}>All</button> :
|
||||||
|
<button className={styles.Filters} onClick={() => this.SwitchGroupList('All')}>All</button>}
|
||||||
|
|
||||||
|
{this.state.mode === 'Private' ? <button className={styles.SelectedFilter} onClick={() => this.SwitchGroupList('Private')}>Private</button> :
|
||||||
|
<button className={styles.Filters} onClick={() => this.SwitchGroupList('Private')}>Private</button>}</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div className={styles.tableStyle}>
|
||||||
|
<div className={styles.headerStyle}>
|
||||||
|
<div className={styles.Center}>Team</div>
|
||||||
|
<div className={styles.Center}>Mail</div>
|
||||||
|
<div className={styles.Center}>Site</div>
|
||||||
|
<div className={styles.Center}>Calendar</div>
|
||||||
|
<div className={styles.Center}>Planner</div>
|
||||||
|
<div className={styles.Center}>WebUrl</div>
|
||||||
|
<div className={styles.Center} style={{ borderRight: 'none' }}>Visibility</div>
|
||||||
|
</div>
|
||||||
|
{this.state.MyGroupsresultsFiltered.map(Team => {
|
||||||
|
Team.Visibility = Team.Visibility.substr(0, 1).toUpperCase() + Team.Visibility.substr(1);
|
||||||
|
var GroupEmailSplit = Team.Mail.split("@");
|
||||||
|
var Mail = GroupEmailSplit[0];
|
||||||
|
return (
|
||||||
|
<div className={styles.rowStyle}>
|
||||||
|
<div className={styles.ToolTipName}>{Team.Name}<span className={styles.ToolTip}>{Team.Description}</span></div>
|
||||||
|
<a className={styles.Center} href={`https://outlook.office365.com/mail/group/${this.Tenant}.com/${Mail.toLowerCase()}/email`}>
|
||||||
|
<Icon className={iconClass} style={{ color: '#087CD7' }} iconName="OutlookLogo"></Icon></a>
|
||||||
|
<a className={styles.Center} href={`https://${this.Tenant}.sharepoint.com/sites/${Mail}`}>
|
||||||
|
<Icon className={iconClass} style={{ color: '#068B90' }} iconName="SharePointLogo"></Icon>
|
||||||
|
</a>
|
||||||
|
<a className={styles.Center} href={`https://outlook.office365.com/calendar/group/${this.Tenant}.com/${Team.Name.replace(Replaceregex, '')}/view/week`}>
|
||||||
|
<Icon className={iconClass} style={{ color: '#119AE2' }} iconName="Calendar"></Icon>
|
||||||
|
</a>
|
||||||
|
<div className={styles.Center}>
|
||||||
|
{Team.Planner === undefined ? <div></div> : <a href={Team.Planner}>
|
||||||
|
<Icon className={iconClass} style={{ color: '#077D3F' }} iconName="ViewListTree"></Icon>
|
||||||
|
</a>}
|
||||||
|
</div>
|
||||||
|
<a className={styles.Center} href={`${Team.WebUrl}`}>
|
||||||
|
<Icon className={iconClass} style={{ color: '#424AB5' }} iconName="TeamsLogo"></Icon>
|
||||||
|
</a>
|
||||||
|
<div className={styles.Center} style={{ borderRight: 'none' }}>{Team.Visibility}</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
})}</div></div>;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
define([], function() {
|
||||||
|
return {
|
||||||
|
"PropertyPaneDescription": "Description",
|
||||||
|
"BasicGroupName": "Group Name",
|
||||||
|
"DescriptionFieldLabel": "Description Field"
|
||||||
|
}
|
||||||
|
});
|
|
@ -0,0 +1,10 @@
|
||||||
|
declare interface IMicrosoftGroupsWebPartStrings {
|
||||||
|
PropertyPaneDescription: string;
|
||||||
|
BasicGroupName: string;
|
||||||
|
DescriptionFieldLabel: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare module 'MicrosoftGroupsWebPartStrings' {
|
||||||
|
const strings: IMicrosoftGroupsWebPartStrings;
|
||||||
|
export = strings;
|
||||||
|
}
|
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,36 @@
|
||||||
|
{
|
||||||
|
"extends": "./node_modules/@microsoft/rush-stack-compiler-2.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": [
|
||||||
|
"es6-promise",
|
||||||
|
"webpack-env"
|
||||||
|
],
|
||||||
|
"lib": [
|
||||||
|
"es2015","es2017","dom"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"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