Initial Push- react-groups-teams Version 2.0.0
Updated styling and functionality of web part. Added pagination and page display settings. Combined Groups and Teams tab into one.
|
@ -1,43 +1,30 @@
|
|||
# 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.
|
||||
- Toggle- View groups signed in user is a member of or all groups
|
||||
- Group Name (hover for group description)
|
||||
- Link to Group email
|
||||
- Link to SharePoint site
|
||||
- Link to calendar
|
||||
- Link to Planner plan (if available)
|
||||
- Group privacy filter (Private/Public/All)
|
||||
- Microsoft Teams team link for the Group
|
||||
- Pagination (breaks results into pages and displays page numbers)
|
||||
- Style toggle (Card/Table)
|
||||
- Group display selection
|
||||
1. Select 5, 10, or 15 groups to display per page for the Table display style
|
||||
2. Select 6, 9, and 12 groups to display per page for the Card display style
|
||||
|
||||
- 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)
|
||||
![picture of the web part in action](./assets/Table-Display.png)
|
||||
![picture of the web part in action](./assets/Card-Display.png)
|
||||
![picture of the web part in action](./assets/Theme-Display.png)
|
||||
|
||||
## Compatibility
|
||||
|
||||
| :warning: Important |
|
||||
|:---------------------------|
|
||||
| Every SPFx version is only compatible with specific version(s) of Node.js. In order to be able to build this sample, please ensure that the version of Node on your workstation matches one of the versions listed in this section. This sample will not work on a different version of Node.|
|
||||
|Refer to <https://aka.ms/spfx-matrix> for more information on SPFx compatibility. |
|
||||
|
||||
![SPFx 1.12.1](https://img.shields.io/badge/SPFx-1.12.1-green.svg)
|
||||
![Node.js v14 | v12 | v10](https://img.shields.io/badge/Node.js-v14%20%7C%20v12%20%7C%20v10-green.svg)
|
||||
![SPFx 1.12.1](https://img.shields.io/badge/SPFx-1.12.1-green.svg)
|
||||
![Node.js v14 | v12 | v10](https://img.shields.io/badge/Node.js-v14%20%7C%20v12%20%7C%20v10-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%202019-Not%20compatible-red.svg)
|
||||
![Does not work with SharePoint 2016 (Feature Pack 2)](https://img.shields.io/badge/SharePoint%202016%20(Feature%20Pack%202)-Not%20compatible-red.svg)
|
||||
|
@ -45,16 +32,16 @@ Web part pulls all Microsoft 365 Groups and Teams that the logged in user has ac
|
|||
![Hosted Workbench Compatible](https://img.shields.io/badge/Hosted%20Workbench-Compatible-yellow.svg "Only after API permissions granted")
|
||||
![Compatible with Remote Containers](https://img.shields.io/badge/Remote%20Containers-Compatible-green.svg)
|
||||
|
||||
For more information about SPFx compatibility, please refer to <https://aka.ms/spfx-matrix>
|
||||
|
||||
## Applies to
|
||||
|
||||
- [SharePoint Framework Developer Preview](https://learn.microsoft.com/sharepoint/dev/spfx/sharepoint-framework-overview)
|
||||
- [SharePoint Framework](https://learn.microsoft.com/sharepoint/dev/spfx/sharepoint-framework-overview)
|
||||
* [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)
|
||||
|
||||
## Contributors
|
||||
## Solution
|
||||
|
||||
- [Alison Collins](https://github.com/ReactIntern) ([Blog](https://graphgod.dev), [LinkedIn](https://www.linkedin.com/in/alison-collins-53192b219/))
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
React-Groups-Teams | [Alison Collins](https://github.com/ReactIntern) ([Blog](https://graphgod.dev), [LinkedIn](https://www.linkedin.com/in/alison-collins-53192b219/)) |
|
||||
|
||||
## Version history
|
||||
|
||||
|
@ -63,6 +50,7 @@ For more information about SPFx compatibility, please refer to <https://aka.ms/s
|
|||
| 1.0.0 | April 16, 2021 | Initial release |
|
||||
| 1.0.1 | August 1, 2021 | Fixed references to Office.com |
|
||||
| 1.1.0 | October 8, 2021 | Upgraded to SPFx 1.12.1 for higher compatibility and added Teams Tab deployment support. |
|
||||
| 2.0.0 | February 26, 2023 | Added new styles (card/table), added page display settings/pagination
|
||||
|
||||
## Prerequisites
|
||||
|
||||
|
@ -94,7 +82,7 @@ For more information about SPFx compatibility, please refer to <https://aka.ms/s
|
|||
- 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
|
||||
|
||||
> 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.
|
||||
> 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
|
||||
|
||||
|
@ -107,7 +95,7 @@ This sample illustrates the following concepts on top of the SharePoint Framewor
|
|||
- 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
|
||||
- Passing web part properties to React components
|
||||
|
||||
## Video
|
||||
|
||||
|
@ -128,8 +116,10 @@ For questions regarding this sample, [create a new question](https://github.com/
|
|||
|
||||
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-groups-teams&template=question.yml&sample=react-groups-teams&authors=@ReactIntern&title=react-groups-teams%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-groups-teams" />
|
||||
|
|
After Width: | Height: | Size: 116 KiB |
Before Width: | Height: | Size: 65 KiB |
Before Width: | Height: | Size: 36 KiB |
Before Width: | Height: | Size: 120 KiB |
Before Width: | Height: | Size: 63 KiB |
After Width: | Height: | Size: 87 KiB |
After Width: | Height: | Size: 67 KiB |
|
@ -22,7 +22,8 @@
|
|||
"@types/webpack-env": "1.13.1",
|
||||
"office-ui-fabric-react": "6.189.2",
|
||||
"react": "16.8.5",
|
||||
"react-dom": "16.8.5"
|
||||
"react-dom": "16.8.5",
|
||||
"tslint-microsoft-contrib": "^6.2.0"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "16.8.8"
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
"scriptResources": {
|
||||
"microsoft-groups-web-part": {
|
||||
"type": "path",
|
||||
"path": "microsoft-groups-web-part_da003a7fb7fd1f14fcb7.js"
|
||||
"path": "microsoft-groups-web-part_c5a309120605c5a62341.js"
|
||||
},
|
||||
"@microsoft/sp-core-library": {
|
||||
"type": "component",
|
||||
|
@ -59,7 +59,7 @@
|
|||
},
|
||||
"MicrosoftGroupsWebPartStrings": {
|
||||
"type": "path",
|
||||
"path": "MicrosoftGroupsWebPartStrings_en-us_b41dd8b4c7f5f69692bd8f24e2b83745.js"
|
||||
"path": "MicrosoftGroupsWebPartStrings_en-us_9cea220c7c0b6131e752012a44ddee44.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
define([], function() {
|
||||
return {
|
||||
"PropertyPaneDescription": "Description",
|
||||
"BasicGroupName": "Group Name",
|
||||
"DescriptionFieldLabel": "Description Field"
|
||||
}
|
||||
});
|
|
@ -35,7 +35,7 @@
|
|||
"scriptResources": {
|
||||
"microsoft-groups-web-part": {
|
||||
"type": "path",
|
||||
"path": "microsoft-groups-web-part_da003a7fb7fd1f14fcb7.js"
|
||||
"path": "microsoft-groups-web-part_c5a309120605c5a62341.js"
|
||||
},
|
||||
"@microsoft/sp-core-library": {
|
||||
"type": "component",
|
||||
|
@ -59,7 +59,7 @@
|
|||
},
|
||||
"MicrosoftGroupsWebPartStrings": {
|
||||
"type": "path",
|
||||
"path": "MicrosoftGroupsWebPartStrings_en-us_b41dd8b4c7f5f69692bd8f24e2b83745.js"
|
||||
"path": "MicrosoftGroupsWebPartStrings_en-us_9cea220c7c0b6131e752012a44ddee44.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
"scriptResources": {
|
||||
"microsoft-groups-web-part": {
|
||||
"type": "path",
|
||||
"path": "microsoft-groups-web-part_da003a7fb7fd1f14fcb7.js"
|
||||
"path": "microsoft-groups-web-part_c5a309120605c5a62341.js"
|
||||
},
|
||||
"@microsoft/sp-core-library": {
|
||||
"type": "component",
|
||||
|
@ -59,7 +59,7 @@
|
|||
},
|
||||
"MicrosoftGroupsWebPartStrings": {
|
||||
"type": "path",
|
||||
"path": "MicrosoftGroupsWebPartStrings_en-us_b41dd8b4c7f5f69692bd8f24e2b83745.js"
|
||||
"path": "MicrosoftGroupsWebPartStrings_en-us_9cea220c7c0b6131e752012a44ddee44.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,14 +4,19 @@ import { Version } from '@microsoft/sp-core-library';
|
|||
import {
|
||||
BaseClientSideWebPart,
|
||||
IPropertyPaneConfiguration,
|
||||
PropertyPaneTextField
|
||||
PropertyPaneChoiceGroup,
|
||||
PropertyPaneTextField,
|
||||
PropertyPaneToggle
|
||||
} from '@microsoft/sp-webpart-base';
|
||||
|
||||
import { IPropertyPaneChoiceGroupOption } from '@microsoft/sp-property-pane';
|
||||
import * as strings from 'MicrosoftGroupsWebPartStrings';
|
||||
import MicrosoftGroups from './components/MicrosoftGroups';
|
||||
import MicrosoftGroups from './components/MicrosoftGroupsTeams';
|
||||
|
||||
export interface IMicrosoftGroupsWebPartProps {
|
||||
description: string;
|
||||
GroupDisplayTable: any;
|
||||
GroupDisplayCard: any;
|
||||
StyleToggle: boolean;
|
||||
}
|
||||
|
||||
export default class MicrosoftGroupsWebPart extends BaseClientSideWebPart<IMicrosoftGroupsWebPartProps> {
|
||||
|
@ -20,7 +25,10 @@ export default class MicrosoftGroupsWebPart extends BaseClientSideWebPart<IMicro
|
|||
const element: React.ReactElement<IMicrosoftGroupsWebPartProps > = React.createElement(
|
||||
MicrosoftGroups,
|
||||
{
|
||||
context: this.context
|
||||
context: this.context,
|
||||
GroupDisplayTable: this.properties.GroupDisplayTable,
|
||||
GroupDisplayCard: this.properties.GroupDisplayCard,
|
||||
StyleToggle: this.properties.StyleToggle
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -34,7 +42,6 @@ export default class MicrosoftGroupsWebPart extends BaseClientSideWebPart<IMicro
|
|||
protected get dataVersion(): Version {
|
||||
return Version.parse('1.0');
|
||||
}
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
return {
|
||||
pages: [
|
||||
|
@ -44,11 +51,28 @@ export default class MicrosoftGroupsWebPart extends BaseClientSideWebPart<IMicro
|
|||
},
|
||||
groups: [
|
||||
{
|
||||
groupName: strings.BasicGroupName,
|
||||
groupFields: [
|
||||
PropertyPaneTextField('description', {
|
||||
label: strings.DescriptionFieldLabel
|
||||
})
|
||||
PropertyPaneToggle('StyleToggle', {
|
||||
label: 'Style',
|
||||
onText: 'Cards',
|
||||
offText: 'Table'
|
||||
}),
|
||||
PropertyPaneChoiceGroup('GroupDisplayTable', {
|
||||
label: 'Group Display - Table Style',
|
||||
options: [
|
||||
{ key: 5, text: '5 Groups', checked: true },
|
||||
{ key: 10, text: '10 Groups'},
|
||||
{ key: 15, text: '15 Groups' }
|
||||
]
|
||||
}),
|
||||
PropertyPaneChoiceGroup('GroupDisplayCard', {
|
||||
label: 'Group Display - Card Style',
|
||||
options: [
|
||||
{ key: 6, text: '6 Groups', checked: true },
|
||||
{ key: 9, text: '9 Groups'},
|
||||
{ key: 12, text: '12 Groups' }
|
||||
]
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
|
@ -0,0 +1,222 @@
|
|||
import * as React from 'react';
|
||||
import { WebPartContext } from '@microsoft/sp-webpart-base';
|
||||
import styles from './MicrosoftGroups.module.scss';
|
||||
import { DocumentCard, DocumentCardDetails, Modal, Stack, ThemeProvider, TooltipHostBase } from 'office-ui-fabric-react';
|
||||
import { Icon } from 'office-ui-fabric-react/lib/Icon';
|
||||
import { iconClass } from './MicrosoftGroupsTeams';
|
||||
|
||||
export interface IGraphConsumerProps {
|
||||
context: WebPartContext;
|
||||
GroupDisplay: number;
|
||||
Mygroups: any [];
|
||||
Allgroups:any[];
|
||||
}
|
||||
export interface IUserItem {
|
||||
Topic: string;
|
||||
DeliveryDate: Date;
|
||||
}
|
||||
|
||||
export interface IGraphConsumerState {
|
||||
mode: string;
|
||||
title: string;
|
||||
GroupResultsFiltered: any;
|
||||
Next: number;
|
||||
Min: number;
|
||||
GroupDisplay: number;
|
||||
}
|
||||
export default class MicrosoftGroups extends React.Component<IGraphConsumerProps, IGraphConsumerState> {
|
||||
public _plannerIDs = [];
|
||||
public _arr = [];
|
||||
public webAbsoluteURL: string = this.props.context.pageContext.web.absoluteUrl;
|
||||
public TenantPathname: string = this.webAbsoluteURL.split('//')[1].split('/')[0];
|
||||
public TenantEmail: string = this.props.context.pageContext.user.loginName.split('@')[1];
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.state = {
|
||||
mode: 'All',
|
||||
title: 'Groups In My Organization',
|
||||
GroupResultsFiltered: [],
|
||||
Next: 6,
|
||||
Min: 0,
|
||||
GroupDisplay: 6
|
||||
};
|
||||
}
|
||||
public SwitchGroupList() {
|
||||
if (this.state.title === 'Groups In My Organization') {
|
||||
this.setState({ title: "My Groups" });
|
||||
this.SwitchGroupList2(this.state.mode, "My Groups");
|
||||
}else {
|
||||
this.setState({ title: 'Groups In My Organization' });
|
||||
this.SwitchGroupList2(this.state.mode, 'Groups In My Organization');
|
||||
}
|
||||
|
||||
}
|
||||
public SwitchGroupList2(Switch:string, title) {
|
||||
if (Switch === 'All') {
|
||||
if(title === 'My Groups') {
|
||||
this.setState({ GroupResultsFiltered: this.props.Mygroups });
|
||||
} else{
|
||||
this.setState({ GroupResultsFiltered: this.props.Allgroups });
|
||||
}
|
||||
}
|
||||
else {
|
||||
var SwitchedValue;
|
||||
if(title === 'My Groups') {
|
||||
SwitchedValue = this.props.Mygroups.filter(item => item.Visibility === Switch);
|
||||
}
|
||||
else{
|
||||
SwitchedValue = this.props.Allgroups.filter(item => item.Visibility === Switch);
|
||||
}
|
||||
this.setState({ GroupResultsFiltered: SwitchedValue});
|
||||
};
|
||||
var nextVariable;
|
||||
if(this.state.GroupDisplay != undefined) {
|
||||
if(!(this.props.GroupDisplay === undefined)) {nextVariable = this.props.GroupDisplay} else {nextVariable = 5;}
|
||||
this.setState({ mode: Switch, Next:nextVariable, Min: 0});
|
||||
}
|
||||
else {
|
||||
nextVariable = 5;
|
||||
this.setState({ mode: Switch, Next:nextVariable, Min: 0, GroupDisplay: 5});}
|
||||
}
|
||||
public componentDidMount() {
|
||||
if (!(this.props.GroupDisplay === undefined || this.props.GroupDisplay ===null)){
|
||||
this.SwitchGroupList2(this.state.mode, this.state.title);
|
||||
this.setState({GroupDisplay: this.props.GroupDisplay, Min:0, Next: this.props.GroupDisplay}) }
|
||||
else {
|
||||
this.SwitchGroupList2(this.state.mode, this.state.title);
|
||||
this.setState({GroupDisplay: 5, Min: 0, Next: 5})
|
||||
}
|
||||
}
|
||||
|
||||
public Next(GroupsFiltered) {
|
||||
var array = [],
|
||||
count = 0,
|
||||
min = this.state.Next,
|
||||
max = min + (this.state.GroupDisplay + 1);
|
||||
GroupsFiltered.map(Group => {
|
||||
count = count + 1;
|
||||
if (count > min && count < max) {
|
||||
array.push(Group);
|
||||
}
|
||||
});
|
||||
var newVal = this.state.Next + this.state.GroupDisplay;
|
||||
this.setState({ Next: newVal, Min: min});
|
||||
}
|
||||
|
||||
public Back(GroupsFiltered) {
|
||||
// comments are as going forward one page and then back. GroupDisplay is set to the default at 5
|
||||
var array = [], //create an array to store the new groups to display
|
||||
max, min, count = 0, //min and max for the range of groups by number and count to get the current level of mapping
|
||||
Above = this.state.Next + this.state.GroupDisplay, //say it's 15
|
||||
FilteredL = this.state.GroupResultsFiltered.length, // How many groups we have in total, say we have 12 total.
|
||||
i = Math.floor(FilteredL / (this.state.GroupDisplay)), //Our group total divided by the limit per page, rounding up so we don't miss groups, 5 goes into 12 twice
|
||||
ifull = i * (this.state.GroupDisplay), //we basically multiply it back out, finding how many pages of full groups we can have. 10
|
||||
Leftover = FilteredL - ifull, // Finding the difference/leftover when we do the math: 12 - 10 = 2
|
||||
difference = (this.state.GroupDisplay) - Leftover; // Finding how much we're missing in the last page: 5 - 2 = 3
|
||||
if((this.state.Next + (this.state.GroupDisplay)) - difference > FilteredL){
|
||||
/*if 10 (remember we're on page 2) + 5 (the current display setting) - 3 (the difference between a full page) > Total Groups
|
||||
//This step matters if you are going back from the last page!! Remember, when we go to the next page we add in increments of 5
|
||||
That means if I were to go to the last page, my Next would be 15 and this statement would be true-
|
||||
15 + 5 - 3 = 17*/
|
||||
max = (FilteredL - Leftover) + 1; // 12 - 2 + 1. We get it back into the 5 increment setting.
|
||||
min = max - this.state.GroupDisplay - 1; // Subtract 5 from the max so we can have a range of 5.
|
||||
/*We just add one because when we map through the Groups we don't have an "or equals to" so it has to be 1 above and under*/
|
||||
}
|
||||
else {
|
||||
// for when it's not the last page we're going back from
|
||||
max = this.state.Next - this.state.GroupDisplay
|
||||
min = max - this.state.GroupDisplay;
|
||||
}
|
||||
GroupsFiltered.map(Group => {
|
||||
count = count + 1;
|
||||
if (count > min && count < max) {
|
||||
array.push(Group);
|
||||
}
|
||||
});
|
||||
var newVal = this.state.Next - (this.state.GroupDisplay);
|
||||
this.setState({ Next: newVal, Min: min });
|
||||
}
|
||||
public componentDidUpdate(prevProps: Readonly<IGraphConsumerProps>): void {
|
||||
if(prevProps.GroupDisplay !== this.props.GroupDisplay) {
|
||||
this.setState({Next: this.props.GroupDisplay, Min: 0, GroupDisplay: this.props.GroupDisplay});
|
||||
}
|
||||
if(prevProps.Allgroups !== this.props.Allgroups || prevProps.Mygroups !== this.props.Mygroups) {
|
||||
this.SwitchGroupList2(this.state.mode, this.state.title);
|
||||
}
|
||||
}
|
||||
|
||||
public render(): React.ReactElement<IGraphConsumerProps> {
|
||||
var i = 0,
|
||||
Replaceregex = /\s+/g;
|
||||
return <div className={styles.Container}>
|
||||
<div className={styles.tableCaptionStyle}>{this.state.title}
|
||||
<div>
|
||||
{this.state.mode === 'Public' ? <button className={styles.SelectedFilter} onClick={() => this.SwitchGroupList2('Public', this.state.title)}>Public</button> :
|
||||
<button className={styles.Filters} onClick={() => this.SwitchGroupList2('Public', this.state.title)}>Public</button>}
|
||||
|
||||
{this.state.mode === 'All' ? <button className={styles.SelectedFilter} onClick={() => this.SwitchGroupList2('All', this.state.title)}>All</button> :
|
||||
<button className={styles.Filters} onClick={() => this.SwitchGroupList2('All', this.state.title)}>All</button>}
|
||||
|
||||
{this.state.mode === 'Private' ? <button className={styles.SelectedFilter} onClick={() => this.SwitchGroupList2('Private', this.state.title)}>Private</button> :
|
||||
<button className={styles.Filters} onClick={() => this.SwitchGroupList2('Private', this.state.title)}>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}>
|
||||
{ this.state.GroupResultsFiltered.map(Group => {
|
||||
var GroupEmailSplit = Group.Mail.split("@");
|
||||
Group.Mail = GroupEmailSplit[0];
|
||||
i = i + 1;
|
||||
if ( i <= this.state.Next && i >= this.state.Min +1) {
|
||||
return <DocumentCard
|
||||
style={{boxShadow: '0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1)',
|
||||
width:'31.65%',
|
||||
height: '144px',
|
||||
paddingBottom: '15px',
|
||||
float: 'left',
|
||||
margin: '6px'
|
||||
}}
|
||||
>
|
||||
<h3 style={{marginBottom: '5px'}}>{Group.Name}</h3>
|
||||
<DocumentCardDetails>
|
||||
<div style={{padding: '0px 4px 0px 4px'}}>{Group.Description}</div>
|
||||
|
||||
<div style={{display:'table-row'}}>
|
||||
<a href={`https://outlook.office.com/mail/group/${this.TenantEmail}/${Group.Mail.toLowerCase()}/email`}>
|
||||
<Icon className={iconClass} style={{ color: '#087CD7', margin:'2px', marginTop:'10px' }} iconName="OutlookLogo"></Icon>
|
||||
</a>
|
||||
<a href={`https://${this.TenantPathname}/sites/${Group.Mail}`}>
|
||||
<Icon className={iconClass} style={{ color: '#068B90', margin:'2px', marginTop:'10px' }} iconName="SharePointLogo"></Icon>
|
||||
</a>
|
||||
<a href={`https://outlook.office.com/calendar/group/${this.TenantEmail}/${Group.Name.replace(Replaceregex, '')}/view/week`}>
|
||||
<Icon className={iconClass} style={{ color: '#119AE2', margin:'2px', marginTop:'10px' }} iconName="Calendar"></Icon>
|
||||
</a>
|
||||
|
||||
<>
|
||||
{Group.Planner === undefined ? <></> : <a href={Group.Planner}>
|
||||
<Icon className={iconClass} style={{ color: '#077D3F', margin:'2px', marginTop:'10px' }} iconName="ViewListTree"></Icon></a>}
|
||||
</>
|
||||
<>{Group.WebUrl === undefined || Group.WebUrl === null ? <></> :
|
||||
<a href={`${Group.WebUrl}`}>
|
||||
<Icon className={iconClass} style={{ color: '#424AB5', margin:'2px', marginTop:'10px' }} iconName="TeamsLogo"></Icon>
|
||||
</a>}</>
|
||||
</div></DocumentCardDetails>
|
||||
</DocumentCard>
|
||||
|
||||
}})}
|
||||
</div>
|
||||
{this.state.GroupResultsFiltered.length === 0 ? <div>There are no items with the selected filters</div>:<></>}
|
||||
<div className={styles.tableStyle}>
|
||||
<div style={{display:'table-row'}}>
|
||||
<div style={{position: 'relative', textAlign:'right', width:'45%', display:'table-cell'}}>
|
||||
<button disabled={this.state.Next === (this.state.GroupDisplay)} onClick={() => this.Back(this.state.GroupResultsFiltered)}>Back</button>
|
||||
</div>
|
||||
<div style={{padding: 8}}>{this.state.Next/this.state.GroupDisplay} of {Math.ceil(this.state.GroupResultsFiltered.length/this.state.GroupDisplay)}</div>
|
||||
<div style={{position: 'relative', textAlign:'left', width:'45%', display:'table-cell'}}>
|
||||
<button disabled={this.state.Next >= this.state.GroupResultsFiltered.length} onClick={() => this.Next(this.state.GroupResultsFiltered)}>Next</button>
|
||||
</div> </div></div>
|
||||
</div>;
|
||||
}
|
||||
}
|
|
@ -1,243 +1,221 @@
|
|||
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';
|
||||
import { iconClass } from './MicrosoftGroupsTeams';
|
||||
|
||||
export interface IGraphConsumerProps {
|
||||
context: WebPartContext;
|
||||
GroupDisplay: number;
|
||||
Mygroups: any [];
|
||||
Allgroups:any[];
|
||||
}
|
||||
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;
|
||||
GroupResultsFiltered: any;
|
||||
Next: number;
|
||||
Min: number;
|
||||
GroupDisplay: number;
|
||||
}
|
||||
export default class MicrosoftGroups extends React.Component<IGraphConsumerProps, IGraphConsumerState> {
|
||||
public _plannerIDs = [];
|
||||
public _arr = [];
|
||||
private graphClient: MSGraphClient = null;
|
||||
public webAbsoluteURL: string = this.props.context.pageContext.web.absoluteUrl;
|
||||
public TenantPathname: string = this.webAbsoluteURL.split('//')[1].split('/')[0];
|
||||
public TenantEmail: string = this.props.context.pageContext.user.loginName.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: []
|
||||
GroupResultsFiltered: [],
|
||||
Next: 5,
|
||||
Min: 0,
|
||||
GroupDisplay: 5,
|
||||
};
|
||||
}
|
||||
public SwitchGroupList() {
|
||||
if (this.state.title === 'Groups In My Organization') {
|
||||
this.setState({ title: "My Groups" });
|
||||
}
|
||||
else {
|
||||
this.SwitchGroupList2(this.state.mode, "My Groups");
|
||||
}else {
|
||||
this.setState({ title: 'Groups In My Organization' });
|
||||
this.SwitchGroupList2(this.state.mode, 'Groups In My Organization');
|
||||
}
|
||||
|
||||
}
|
||||
public SwitchGroupList2(Switch) {
|
||||
public SwitchGroupList2(Switch:string, title) {
|
||||
if (Switch === 'All') {
|
||||
this.setState({ AllGroupsresultsFiltered: this.state.AllGroupsresults });
|
||||
this.setState({ MyGroupResultsFiltered: this.state.MyGroupResults });
|
||||
if(title === 'My Groups') {
|
||||
this.setState({ GroupResultsFiltered: this.props.Mygroups });
|
||||
} else{
|
||||
this.setState({ GroupResultsFiltered: this.props.Allgroups });
|
||||
}
|
||||
}
|
||||
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.TenantEmail}/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) {
|
||||
var SwitchedValue;
|
||||
if(title === 'My Groups') {
|
||||
SwitchedValue = this.props.Mygroups.filter(item => item.Visibility === Switch);
|
||||
}
|
||||
});
|
||||
}
|
||||
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();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
else{
|
||||
SwitchedValue = this.props.Allgroups.filter(item => item.Visibility === Switch);
|
||||
}
|
||||
this.setState({ GroupResultsFiltered: SwitchedValue});
|
||||
};
|
||||
var nextVariable;
|
||||
if(this.state.GroupDisplay != undefined) {
|
||||
if(!(this.props.GroupDisplay === undefined)) {nextVariable = this.props.GroupDisplay} else {nextVariable = 5;}
|
||||
this.setState({ mode: Switch, Next:nextVariable, Min: 0});
|
||||
}
|
||||
else {
|
||||
nextVariable = 5;
|
||||
this.setState({ mode: Switch, Next:nextVariable, Min: 0, GroupDisplay: 5});}
|
||||
}
|
||||
public componentDidMount() {
|
||||
this.GetGroups();
|
||||
if (!(this.props.GroupDisplay === undefined || this.props.GroupDisplay ===null)){
|
||||
this.SwitchGroupList2(this.state.mode, this.state.title);
|
||||
this.setState({GroupDisplay: this.props.GroupDisplay, Min:0, Next: this.props.GroupDisplay}) }
|
||||
else {
|
||||
this.SwitchGroupList2(this.state.mode, this.state.title);
|
||||
this.setState({GroupDisplay: 5, Min: 0, Next: 5})
|
||||
}
|
||||
}
|
||||
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>}
|
||||
public Next(GroupsFiltered) {
|
||||
var array = [],
|
||||
count = 0,
|
||||
min = this.state.Next,
|
||||
max = min + (this.state.GroupDisplay + 1);
|
||||
GroupsFiltered.map(Group => {
|
||||
count = count + 1;
|
||||
if (count > min && count < max) {
|
||||
array.push(Group);
|
||||
}
|
||||
});
|
||||
var newVal = this.state.Next + this.state.GroupDisplay;
|
||||
this.setState({ Next: newVal, Min: min});
|
||||
}
|
||||
|
||||
{this.state.mode === 'Private' ? <button className={styles.SelectedFilter} onClick={() => this.SwitchGroupList2('Private')}>Private</button> :
|
||||
<button className={styles.Filters} onClick={() => this.SwitchGroupList2('Private')}>Private</button>}
|
||||
public Back(GroupsFiltered) {
|
||||
// comments are as going forward one page and then back. GroupDisplay is set to the default at 5
|
||||
var array = [], //create an array to store the new groups to display
|
||||
max, min, count = 0, //min and max for the range of groups by number and count to get the current level of mapping
|
||||
Above = this.state.Next + this.state.GroupDisplay, //say it's 15
|
||||
FilteredL = this.state.GroupResultsFiltered.length, // How many groups we have in total, say we have 12 total.
|
||||
i = Math.floor(FilteredL / (this.state.GroupDisplay)), //Our group total divided by the limit per page, rounding up so we don't miss groups, 5 goes into 12 twice
|
||||
ifull = i * (this.state.GroupDisplay), //we basically multiply it back out, finding how many pages of full groups we can have. 10
|
||||
Leftover = FilteredL - ifull, // Finding the difference/leftover when we do the math: 12 - 10 = 2
|
||||
difference = (this.state.GroupDisplay) - Leftover; // Finding how much we're missing in the last page: 5 - 2 = 3
|
||||
if((this.state.Next + (this.state.GroupDisplay)) - difference > FilteredL){
|
||||
/*if 10 (remember we're on page 2) + 5 (the current display setting) - 3 (the difference between a full page) > Total Groups
|
||||
//This step matters if you are going back from the last page!! Remember, when we go to the next page we add in increments of 5
|
||||
That means if I were to go to the last page, my Next would be 15 and this statement would be true-
|
||||
15 + 5 - 3 = 17*/
|
||||
max = (FilteredL - Leftover) + 1; // 12 - 2 + 1. We get it back into the 5 increment setting.
|
||||
min = max - this.state.GroupDisplay - 1; // Subtract 5 from the max so we can have a range of 5.
|
||||
/*We just add one because when we map through the Groups we don't have an "or equals to" so it has to be 1 above and under*/
|
||||
}
|
||||
else {
|
||||
// for when it's not the last page we're going back from
|
||||
max = this.state.Next - this.state.GroupDisplay
|
||||
min = max - this.state.GroupDisplay;
|
||||
}
|
||||
GroupsFiltered.map(Group => {
|
||||
count = count + 1;
|
||||
if (count > min && count < max) {
|
||||
array.push(Group);
|
||||
}
|
||||
});
|
||||
var newVal = this.state.Next - (this.state.GroupDisplay);
|
||||
this.setState({ Next: newVal, Min: min });
|
||||
}
|
||||
public componentDidUpdate(prevProps: Readonly<IGraphConsumerProps>): void {
|
||||
if(prevProps.GroupDisplay !== this.props.GroupDisplay) {
|
||||
this.setState({Next: this.props.GroupDisplay, Min: 0, GroupDisplay: this.props.GroupDisplay});
|
||||
}
|
||||
if(prevProps.Allgroups !== this.props.Allgroups || prevProps.Mygroups !== this.props.Mygroups) {
|
||||
this.SwitchGroupList2(this.state.mode, this.state.title);
|
||||
}
|
||||
}
|
||||
|
||||
public render(): React.ReactElement<IGraphConsumerProps> {debugger;
|
||||
var NextButton,
|
||||
BackButton,
|
||||
i = 0,
|
||||
Replaceregex = /\s+/g;
|
||||
this.state.Next >= this.state.GroupResultsFiltered.length ? NextButton = styles.DisButton : NextButton = styles.NavButton;
|
||||
this.state.Next === (this.state.GroupDisplay) ? BackButton = styles.DisButton : BackButton = styles.NavButton;
|
||||
return <div className={styles.Container}>
|
||||
<div className={styles.tableCaptionStyle}>{this.state.title}
|
||||
<div>
|
||||
{this.state.mode === 'Public' ? <button className={styles.SelectedFilter} onClick={() => this.SwitchGroupList2('Public', this.state.title)}>Public</button> :
|
||||
<button className={styles.Filters} onClick={() => this.SwitchGroupList2('Public', this.state.title)}>Public</button>}
|
||||
|
||||
{this.state.mode === 'All' ? <button className={styles.SelectedFilter} onClick={() => this.SwitchGroupList2('All', this.state.title)}>All</button> :
|
||||
<button className={styles.Filters} onClick={() => this.SwitchGroupList2('All', this.state.title)}>All</button>}
|
||||
|
||||
{this.state.mode === 'Private' ? <button className={styles.SelectedFilter} onClick={() => this.SwitchGroupList2('Private', this.state.title)}>Private</button> :
|
||||
<button className={styles.Filters} onClick={() => this.SwitchGroupList2('Private', this.state.title)}>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}>
|
||||
<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}>Teams</div>
|
||||
<div className={styles.Center} style={{ borderRight: 'none' }}>Visibility</div>
|
||||
</div>
|
||||
{ this.state.GroupResultsFiltered.map(Group => {
|
||||
var GroupEmailSplit = Group.Mail.split("@");
|
||||
Group.Mail = GroupEmailSplit[0];
|
||||
i = i + 1;
|
||||
if ( i <= this.state.Next && i >= this.state.Min +1) {
|
||||
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.office.com/mail/group/${this.TenantEmail}/${Group.Mail.toLowerCase()}/email`}>
|
||||
<Icon className={iconClass} style={{ color: '#087CD7' }} iconName="OutlookLogo"></Icon>
|
||||
</a>
|
||||
<a className={styles.Center} href={`https://${this.TenantPathname}/sites/${Group.Mail}`}>
|
||||
<Icon className={iconClass} style={{ color: '#068B90' }} iconName="SharePointLogo"></Icon>
|
||||
</a>
|
||||
<a className={styles.Center} href={`https://outlook.office.com/calendar/group/${this.TenantEmail}/${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>
|
||||
{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.office.com/mail/group/${this.TenantEmail}/${Group.Mail.toLowerCase()}/email`}>
|
||||
<Icon className={iconClass} style={{ color: '#087CD7' }} iconName="OutlookLogo"></Icon>
|
||||
</a>
|
||||
<a className={styles.Center} href={`https://${this.TenantPathname}/sites/${Group.Mail}`}>
|
||||
<Icon className={iconClass} style={{ color: '#068B90' }} iconName="SharePointLogo"></Icon>
|
||||
</a>
|
||||
<a className={styles.Center} href={`https://outlook.office.com/calendar/group/${this.TenantEmail}/${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.office.com/mail/group/${this.TenantEmail}/${Group.Mail.toLowerCase()}/email`}>
|
||||
<Icon className={iconClass} style={{ color: '#087CD7' }} iconName="OutlookLogo"></Icon>
|
||||
</a>
|
||||
<a className={styles.Center} href={`https://${this.TenantPathname}/sites/${Group.Mail}`}>
|
||||
<Icon className={iconClass} style={{ color: '#068B90' }} iconName="SharePointLogo"></Icon>
|
||||
</a>
|
||||
<a className={styles.Center} href={`https://outlook.office.com/calendar/group/${this.TenantEmail}/${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>;
|
||||
}
|
||||
<div className={styles.Center}>{Group.WebUrl === undefined || Group.WebUrl === null ? <div></div> :
|
||||
<a href={`${Group.WebUrl}`}>
|
||||
<Icon className={iconClass} style={{ color: '#424AB5' }} iconName="TeamsLogo"></Icon>
|
||||
</a>}</div>
|
||||
<div className={styles.Center} style={{ borderRight: 'none' }}>{Group.Visibility}</div>
|
||||
</div>}})}
|
||||
</div>
|
||||
{this.state.GroupResultsFiltered.length === 0 ? <div>There are no items with the selected filters</div>:<></>}
|
||||
<div className={styles.tableStyle}>
|
||||
<div style={{display:'table-row'}}>
|
||||
<div style={{position: 'relative', textAlign:'right', width:'45%', display:'table-cell'}}>
|
||||
<button className={BackButton} disabled={this.state.Next === (this.state.GroupDisplay)} onClick={() => this.Back(this.state.GroupResultsFiltered)}>Back</button>
|
||||
</div>
|
||||
<div style={{padding: 8}}>{this.state.Next/this.state.GroupDisplay} of {Math.ceil(this.state.GroupResultsFiltered.length/this.state.GroupDisplay)}</div>
|
||||
<div style={{position: 'relative', textAlign:'left', width:'45%', display:'table-cell'}}>
|
||||
<button className={NextButton} disabled={this.state.Next >= this.state.GroupResultsFiltered.length} onClick={() => this.Next(this.state.GroupResultsFiltered)}>Next</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,92 +1,83 @@
|
|||
@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;
|
||||
|
||||
.Center {
|
||||
padding: 3px 1px 0px;
|
||||
margin-left: 26px;
|
||||
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;
|
||||
max-width: 113px;
|
||||
word-break: break-word;
|
||||
}
|
||||
.SwitchGroups{
|
||||
position:absolute;
|
||||
bottom:6px;
|
||||
right:6px;
|
||||
font-size:16px;
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
cursor:pointer;
|
||||
color:white;
|
||||
}
|
||||
.SwitchGroups:hover{
|
||||
text-decoration: underline;
|
||||
}
|
||||
.headerStyle{
|
||||
}
|
||||
.SwitchGroups:hover{
|
||||
text-decoration: underline;
|
||||
}
|
||||
.NavButton {
|
||||
padding: 8px;
|
||||
background-color: "[theme: themePrimary, default: #0078d7]";
|
||||
color: white;
|
||||
border: none;
|
||||
}
|
||||
.DisButton {
|
||||
padding: 8px;
|
||||
color: white;
|
||||
border: none;
|
||||
background-color: "[theme: themeLight, default: #0078d7]";
|
||||
}
|
||||
.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 ;
|
||||
}
|
||||
border: solid ;
|
||||
text-align : center ;
|
||||
width : 100px ;
|
||||
height : 30px ;
|
||||
padding-top : 10px ;
|
||||
color : white ;
|
||||
}
|
||||
.tableStyle{
|
||||
display: table;
|
||||
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: none;
|
||||
text-align:center ;
|
||||
height:79px;
|
||||
padding-top:9px;
|
||||
color:white;
|
||||
border-top: 2px solid white;
|
||||
border-bottom: 2px solid white;
|
||||
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;
|
||||
|
@ -94,22 +85,14 @@
|
|||
padding: 20px;
|
||||
}
|
||||
.CellStyle{
|
||||
display: table-cell ;
|
||||
border: solid ;
|
||||
border-color : white ;
|
||||
text-align : center ;
|
||||
min-width : 75px ;
|
||||
height : 30px ;
|
||||
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 ;
|
||||
padding-top: 10px;
|
||||
}
|
||||
.column {
|
||||
@include ms-Grid-col;
|
||||
|
@ -118,64 +101,10 @@
|
|||
@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 {
|
||||
.Container {
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.none {
|
||||
display:none;
|
||||
height:100%
|
||||
}
|
||||
.CenterRight {
|
||||
border-right:none;
|
||||
|
@ -184,19 +113,6 @@
|
|||
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;
|
||||
}
|
||||
|
@ -206,7 +122,6 @@
|
|||
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;
|
||||
|
@ -218,7 +133,6 @@
|
|||
background-color: $ms-color-themeDark;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
border-radius: 6px;
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
bottom: 86%;
|
||||
|
@ -233,7 +147,7 @@
|
|||
background-color: "[theme: themeLight, default: #0078d7]";
|
||||
}
|
||||
.MainViewCenter {
|
||||
width: 50%;
|
||||
width: 45%;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
display: table-cell;
|
||||
|
@ -242,10 +156,8 @@
|
|||
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{
|
||||
|
@ -256,170 +168,22 @@
|
|||
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;
|
||||
padding: 4px;
|
||||
}
|
||||
.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;}
|
||||
background-color: "[theme: themeDark, default: #0078d7]";
|
||||
color: #fff;
|
||||
border: none;
|
||||
margin-right: 4px;
|
||||
margin-top: 9px;
|
||||
padding: 4px;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
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,214 @@
|
|||
import * as React from 'react';
|
||||
import { MSGraphClient } from "@microsoft/sp-http";
|
||||
import { WebPartContext } from '@microsoft/sp-webpart-base';
|
||||
import GraphConsumer from './Microsoft365Groups';
|
||||
import CardStyle from './CardStyle';
|
||||
import { mergeStyles } from 'office-ui-fabric-react/lib/Styling';
|
||||
export interface IMicrosoftGroupsProps {
|
||||
context: WebPartContext;
|
||||
GroupDisplayTable: any;
|
||||
GroupDisplayCard: any;
|
||||
StyleToggle: boolean;
|
||||
}
|
||||
|
||||
export interface IMicrosoftGroupsState {
|
||||
AllGroupsresults: any;
|
||||
MyGroupResults: any;
|
||||
GroupDisplayTable: number;
|
||||
GroupDisplayCard: number;
|
||||
StyleToggle: boolean;
|
||||
}
|
||||
export const iconClass = mergeStyles({
|
||||
fontSize: 32,
|
||||
height: 32,
|
||||
width: 32
|
||||
});
|
||||
|
||||
export default class MicrosoftGroups extends React.Component<IMicrosoftGroupsProps, IMicrosoftGroupsState> {
|
||||
public _plannerIDs = [];
|
||||
public _arr = [];
|
||||
private graphClient: MSGraphClient = null;
|
||||
public webAbsoluteURL: string = this.props.context.pageContext.web.absoluteUrl;
|
||||
public TenantPathname: string = this.webAbsoluteURL.split('//')[1].split('/')[0];
|
||||
public TenantEmail: string = this.props.context.pageContext.user.loginName.split('@')[1];
|
||||
constructor(props) {
|
||||
super(props);
|
||||
this.GetPlanner = this.GetPlanner.bind(this);
|
||||
this.GetGroups = this.GetGroups.bind(this);
|
||||
this.state = {
|
||||
AllGroupsresults: [],
|
||||
MyGroupResults: [],
|
||||
GroupDisplayTable: 5,
|
||||
GroupDisplayCard: 6,
|
||||
StyleToggle: false
|
||||
};
|
||||
}
|
||||
|
||||
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.TenantEmail}/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;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.setState({ MyGroupResults: this.state.MyGroupResults });
|
||||
} catch (error) {}
|
||||
});
|
||||
this.GetTeams();
|
||||
}
|
||||
|
||||
public async GetTeams() {
|
||||
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.GetTeamsURL(array);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
public GetTeamsURL(Teams) {
|
||||
Teams.map(Team => {
|
||||
this.props.context.msGraphClientFactory
|
||||
.getClient()
|
||||
.then((client: MSGraphClient): void => {
|
||||
client
|
||||
.api(`/teams/${Team.Id}/?$select=webUrl`)
|
||||
.version("v1.0")
|
||||
.get((err, res) => {
|
||||
if (err) {
|
||||
return;
|
||||
}
|
||||
if (res) {
|
||||
var URL = (res.webUrl.split('conversations')[0] + '/General' + res.webUrl.split('conversations')[1]),
|
||||
webUrl = { WebUrl: URL },
|
||||
Results = Object.assign(Team, { WebUrl: webUrl });
|
||||
Team = Results;
|
||||
this.state.MyGroupResults.map(Group => {
|
||||
if (Group.Name === Team.Name) {
|
||||
var Results2 = Object.assign(Group, webUrl);
|
||||
Group = Results2;
|
||||
}
|
||||
});
|
||||
this.state.AllGroupsresults.map(Group => {
|
||||
if (Group.Name === Team.Name) {
|
||||
var Results2 = Object.assign(Group, webUrl);
|
||||
Group = Results2;
|
||||
}
|
||||
});
|
||||
this.setState({ AllGroupsresults: this.state.AllGroupsresults, MyGroupResults: this.state.MyGroupResults});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
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({ 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 });
|
||||
this.GetPlanner();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
public componentDidMount() {
|
||||
this.GetGroups();
|
||||
this.setState({GroupDisplayTable: this.props.GroupDisplayTable, GroupDisplayCard: this.props.GroupDisplayCard});
|
||||
}
|
||||
public componentDidUpdate(prevProps: Readonly<IMicrosoftGroupsProps>): void {
|
||||
if(prevProps.GroupDisplayTable !== this.props.GroupDisplayTable) { //needed to prevent exceeding maximum update update depth
|
||||
this.setState({GroupDisplayTable: this.props.GroupDisplayTable});
|
||||
}
|
||||
if(prevProps.GroupDisplayCard !== this.props.GroupDisplayCard) {
|
||||
this.setState({GroupDisplayCard: this.props.GroupDisplayCard});
|
||||
}
|
||||
if (prevProps.StyleToggle !== this.props.StyleToggle && this.props.StyleToggle!== undefined){
|
||||
this.setState({StyleToggle: this.props.StyleToggle})
|
||||
}
|
||||
|
||||
}
|
||||
public render(): React.ReactElement<IMicrosoftGroupsProps> {
|
||||
return <div>
|
||||
{this.state.StyleToggle === false ?
|
||||
<GraphConsumer
|
||||
context={this.props.context}
|
||||
GroupDisplay={this.state.GroupDisplayTable}
|
||||
Mygroups={this.state.MyGroupResults}
|
||||
Allgroups={this.state.AllGroupsresults}/>
|
||||
:
|
||||
<CardStyle
|
||||
context={this.props.context}
|
||||
GroupDisplay={this.props.GroupDisplayCard}
|
||||
Mygroups={this.state.MyGroupResults}
|
||||
Allgroups={this.state.AllGroupsresults}/>
|
||||
}
|
||||
</div>
|
||||
}
|
||||
}
|
|
@ -1,202 +0,0 @@
|
|||
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 webAbsoluteURL: string = this.props.context.pageContext.web.absoluteUrl;
|
||||
public TenantPathname: string = this.webAbsoluteURL.split('//')[1].split('/')[0];
|
||||
public TenantEmail: string = this.props.context.pageContext.user.loginName.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.TenantEmail}/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.office.com/mail/group/${this.TenantEmail}/${Mail.toLowerCase()}/email`}>
|
||||
<Icon className={iconClass} style={{ color: '#087CD7' }} iconName="OutlookLogo"></Icon></a>
|
||||
<a className={styles.Center} href={`https://${this.TenantPathname}/sites/${Mail}`}>
|
||||
<Icon className={iconClass} style={{ color: '#068B90' }} iconName="SharePointLogo"></Icon>
|
||||
</a>
|
||||
<a className={styles.Center} href={`https://outlook.office.com/calendar/group/${this.TenantEmail}/${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>;
|
||||
}
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
define([], function() {
|
||||
return {
|
||||
"PropertyPaneDescription": "Description",
|
||||
"BasicGroupName": "Group Name",
|
||||
"PropertyPaneDescription": "Your Microsoft Groups and Teams",
|
||||
"DescriptionFieldLabel": "Description Field"
|
||||
}
|
||||
});
|
|
@ -33,4 +33,4 @@
|
|||
"node_modules",
|
||||
"lib"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
"no-switch-case-fall-through": true,
|
||||
"no-unnecessary-semicolons": true,
|
||||
"no-unused-expression": true,
|
||||
"no-use-before-declare": true,
|
||||
"no-use-before-declare": false,
|
||||
"no-with-statement": true,
|
||||
"semicolon": true,
|
||||
"trailing-comma": false,
|
||||
|
|