Updated React Graph Calendar to SPFx 1.10 + adding Personal Tab support (#1111)
Updated React Graph Calendar to SPFx 1.10 + adding Personal Tab support (#1111)
This commit is contained in:
parent
e636d68221
commit
11da7ad89d
|
@ -1,7 +1,7 @@
|
||||||
# React Graph Calendar Web Part
|
# React Graph Calendar Web Part
|
||||||
|
|
||||||
## Summary
|
## Summary
|
||||||
This is a sample web part developed using React Framework to gather events from the underlying group calendar of a Team site. This sample also demonstrates the utilization of web parts as Teams tabs and offering a visualization context to change behaviors based on the platform used (Getting the proper information from the team vs. SharePoint site, understanding the context of the theme on Teams, etc.).
|
This is a sample web part developed using React Framework to gather events from the underlying group calendar of a Team site. This sample also demonstrates the utilization of web parts as Teams tabs and Personal tab and offering a visualization context to change behaviors based on the platform used (Getting the proper information from the team vs. SharePoint site, understanding the context of the theme on Teams, etc.).
|
||||||
|
|
||||||
### Web Part in SharePoint Online
|
### Web Part in SharePoint Online
|
||||||
![The web part in action](./assets/react-graph-calendar-spo.gif)
|
![The web part in action](./assets/react-graph-calendar-spo.gif)
|
||||||
|
@ -16,7 +16,7 @@ Webpart is developed using below technologies
|
||||||
* Office UI Fabric
|
* Office UI Fabric
|
||||||
|
|
||||||
## Used SharePoint Framework Version
|
## Used SharePoint Framework Version
|
||||||
![drop](https://img.shields.io/badge/version-1.9.1-green.svg)
|
![drop](https://img.shields.io/badge/version-1.10-green.svg)
|
||||||
|
|
||||||
## Applies to
|
## Applies to
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@ react-graph-calendar | [Sébastien Levert](https://www.linkedin.com/in/sebastien
|
||||||
Version|Date|Comments
|
Version|Date|Comments
|
||||||
-------|----|--------
|
-------|----|--------
|
||||||
1.0 |December 29, 2019 | Initial Release
|
1.0 |December 29, 2019 | Initial Release
|
||||||
|
1.1 |January 08, 2020 | Bumped to SPFx 1.10 and added the Personal Tab support
|
||||||
|
|
||||||
## Disclaimer
|
## 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.**
|
**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.**
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 9.1 MiB After Width: | Height: | Size: 5.2 MiB |
Binary file not shown.
Before Width: | Height: | Size: 9.3 MiB After Width: | Height: | Size: 8.7 MiB |
|
@ -11,6 +11,10 @@
|
||||||
{
|
{
|
||||||
"resource": "Microsoft Graph",
|
"resource": "Microsoft Graph",
|
||||||
"scope": "Group.Read.All"
|
"scope": "Group.Read.All"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resource": "Microsoft Graph",
|
||||||
|
"scope": "Calendars.Read"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -17,10 +17,10 @@
|
||||||
"@fullcalendar/moment": "^4.3.0",
|
"@fullcalendar/moment": "^4.3.0",
|
||||||
"@fullcalendar/moment-timezone": "^4.3.0",
|
"@fullcalendar/moment-timezone": "^4.3.0",
|
||||||
"@fullcalendar/react": "^4.3.0",
|
"@fullcalendar/react": "^4.3.0",
|
||||||
"@microsoft/sp-core-library": "1.9.1",
|
"@microsoft/sp-core-library": "1.10.0",
|
||||||
"@microsoft/sp-lodash-subset": "1.9.1",
|
"@microsoft/sp-lodash-subset": "1.10.0",
|
||||||
"@microsoft/sp-office-ui-fabric-core": "1.9.1",
|
"@microsoft/sp-office-ui-fabric-core": "1.10.0",
|
||||||
"@microsoft/sp-webpart-base": "1.9.1",
|
"@microsoft/sp-webpart-base": "1.10.0",
|
||||||
"@types/es6-promise": "0.0.33",
|
"@types/es6-promise": "0.0.33",
|
||||||
"@types/react": "16.8.8",
|
"@types/react": "16.8.8",
|
||||||
"@types/react-dom": "16.8.3",
|
"@types/react-dom": "16.8.3",
|
||||||
|
@ -35,10 +35,10 @@
|
||||||
"@types/react": "16.8.8"
|
"@types/react": "16.8.8"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@microsoft/sp-build-web": "1.9.1",
|
"@microsoft/sp-build-web": "1.10.0",
|
||||||
"@microsoft/sp-tslint-rules": "1.9.1",
|
"@microsoft/sp-tslint-rules": "1.10.0",
|
||||||
"@microsoft/sp-module-interfaces": "1.9.1",
|
"@microsoft/sp-module-interfaces": "1.10.0",
|
||||||
"@microsoft/sp-webpart-workbench": "1.9.1",
|
"@microsoft/sp-webpart-workbench": "1.10.0",
|
||||||
"@microsoft/rush-stack-compiler-2.9": "0.7.16",
|
"@microsoft/rush-stack-compiler-2.9": "0.7.16",
|
||||||
"gulp": "~3.9.1",
|
"gulp": "~3.9.1",
|
||||||
"@types/chai": "3.4.34",
|
"@types/chai": "3.4.34",
|
||||||
|
|
|
@ -12,13 +12,13 @@
|
||||||
// Components that allow authors to embed arbitrary script code should set this to true.
|
// 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
|
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
|
||||||
"requiresCustomScript": false,
|
"requiresCustomScript": false,
|
||||||
"supportedHosts": ["SharePointWebPart", "TeamsTab"],
|
"supportedHosts": ["SharePointWebPart", "TeamsTab", "TeamsPersonalApp"],
|
||||||
"preconfiguredEntries": [{
|
"preconfiguredEntries": [{
|
||||||
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
|
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
|
||||||
"group": { "default": "Other" },
|
"group": { "default": "Other" },
|
||||||
"title": { "default": "Graph Calendar" },
|
"title": { "default": "Graph Calendar" },
|
||||||
"description": { "default": "GraphCalendar description" },
|
"description": { "default": "Graph Calendar" },
|
||||||
"officeFabricIconFontName": "Page",
|
"officeFabricIconFontName": "Calendar",
|
||||||
"properties": {
|
"properties": {
|
||||||
"description": "Graph Calendar"
|
"description": "Graph Calendar"
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,15 +44,14 @@ export default class GraphCalendarWebPart extends BaseClientSideWebPart<IGraphCa
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the Teams context if in Teams
|
// Sets the Teams context if in Teams
|
||||||
if (this.context.microsoftTeams) {
|
if (this.context.sdks.microsoftTeams) {
|
||||||
this.context.microsoftTeams.getContext(context => {
|
this._teamsContext = this.context.sdks.microsoftTeams.context;
|
||||||
this._teamsContext = context;
|
|
||||||
// resolve the promise
|
|
||||||
resolve(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Initialize the OUIF icons if in Teams
|
// Initialize the OUIF icons if in Teams
|
||||||
initializeIcons();
|
initializeIcons();
|
||||||
|
|
||||||
|
// resolve the promise
|
||||||
|
resolve(undefined);
|
||||||
} else {
|
} else {
|
||||||
// resolve the promise
|
// resolve the promise
|
||||||
resolve(undefined);
|
resolve(undefined);
|
||||||
|
|
|
@ -17,6 +17,12 @@ interface IGraphCalendarState {
|
||||||
isEventDetailsOpen: boolean;
|
isEventDetailsOpen: boolean;
|
||||||
currentSelectedEvent: EventInput;
|
currentSelectedEvent: EventInput;
|
||||||
groupId: string;
|
groupId: string;
|
||||||
|
tabType: TabType;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum TabType {
|
||||||
|
TeamsTab,
|
||||||
|
PersonalTab
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class GraphCalendar extends React.Component<IGraphCalendarProps, IGraphCalendarState> {
|
export default class GraphCalendar extends React.Component<IGraphCalendarProps, IGraphCalendarState> {
|
||||||
|
@ -45,7 +51,8 @@ export default class GraphCalendar extends React.Component<IGraphCalendarProps,
|
||||||
currentActiveEndDate: null,
|
currentActiveEndDate: null,
|
||||||
isEventDetailsOpen: false,
|
isEventDetailsOpen: false,
|
||||||
currentSelectedEvent: null,
|
currentSelectedEvent: null,
|
||||||
groupId: this._isRunningInTeams() ? this.props.teamsContext.groupId : this.props.context.pageContext.site.group ? this.props.context.pageContext.site.group.id : ""
|
groupId: this._isRunningInTeams() ? this.props.teamsContext.groupId : this.props.context.pageContext.site.group ? this.props.context.pageContext.site.group.id : "",
|
||||||
|
tabType: this._isRunningInTeams() ? (this._isPersonalTab() ? TabType.PersonalTab : TabType.TeamsTab) : TabType.TeamsTab
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +80,7 @@ export default class GraphCalendar extends React.Component<IGraphCalendarProps,
|
||||||
plugins={[ dayGridPlugin ]}
|
plugins={[ dayGridPlugin ]}
|
||||||
windowResize={this._handleResize.bind(this)}
|
windowResize={this._handleResize.bind(this)}
|
||||||
datesRender={this._datesRender.bind(this)}
|
datesRender={this._datesRender.bind(this)}
|
||||||
eventClick={this._handleEventClick.bind(this)}
|
eventClick={this._openEventPanel.bind(this)}
|
||||||
height={this.state.height}
|
height={this.state.height}
|
||||||
events={this.state.events} />
|
events={this.state.events} />
|
||||||
{this.state.currentSelectedEvent &&
|
{this.state.currentSelectedEvent &&
|
||||||
|
@ -81,6 +88,8 @@ export default class GraphCalendar extends React.Component<IGraphCalendarProps,
|
||||||
isOpen={this.state.isEventDetailsOpen}
|
isOpen={this.state.isEventDetailsOpen}
|
||||||
type={ PanelType.smallFixedFar }
|
type={ PanelType.smallFixedFar }
|
||||||
headerText={this.state.currentSelectedEvent ? this.state.currentSelectedEvent.title : ""}
|
headerText={this.state.currentSelectedEvent ? this.state.currentSelectedEvent.title : ""}
|
||||||
|
onDismiss={this._closeEventPanel.bind(this)}
|
||||||
|
isLightDismiss={true}
|
||||||
closeButtonAriaLabel='Close'>
|
closeButtonAriaLabel='Close'>
|
||||||
<h3>Start Time</h3>
|
<h3>Start Time</h3>
|
||||||
<span>{moment(this.state.currentSelectedEvent.start).format('MMMM Do YYYY [at] h:mm:ss a')}</span>
|
<span>{moment(this.state.currentSelectedEvent.start).format('MMMM Do YYYY [at] h:mm:ss a')}</span>
|
||||||
|
@ -123,17 +132,40 @@ export default class GraphCalendar extends React.Component<IGraphCalendarProps,
|
||||||
return this.props.teamsContext;
|
return this.props.teamsContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validates if the current web part is running in a Personal Tab
|
||||||
|
*/
|
||||||
|
private _isPersonalTab() {
|
||||||
|
let _isPersonalTab: Boolean = false;
|
||||||
|
|
||||||
|
if(this._isRunningInTeams() && !this.props.teamsContext.teamId) {
|
||||||
|
_isPersonalTab = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return _isPersonalTab;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles the click event and opens the OUIF Panel
|
* Handles the click event and opens the OUIF Panel
|
||||||
* @param eventClickInfo The information about the selected event
|
* @param eventClickInfo The information about the selected event
|
||||||
*/
|
*/
|
||||||
private _handleEventClick(eventClickInfo: any) {
|
private _openEventPanel(eventClickInfo: any) {
|
||||||
this.setState({
|
this.setState({
|
||||||
isEventDetailsOpen: true,
|
isEventDetailsOpen: true,
|
||||||
currentSelectedEvent: eventClickInfo.event
|
currentSelectedEvent: eventClickInfo.event
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles the click event on the dismiss from the Panel and closes the OUIF Panel
|
||||||
|
*/
|
||||||
|
private _closeEventPanel() {
|
||||||
|
this.setState({
|
||||||
|
isEventDetailsOpen: true,
|
||||||
|
currentSelectedEvent: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the view changed, reload the events based on the active view
|
* If the view changed, reload the events based on the active view
|
||||||
* @param info Information about the current active view
|
* @param info Information about the current active view
|
||||||
|
@ -166,15 +198,20 @@ export default class GraphCalendar extends React.Component<IGraphCalendarProps,
|
||||||
*/
|
*/
|
||||||
private _loadEvents(startDate: Date, endDate: Date): void {
|
private _loadEvents(startDate: Date, endDate: Date): void {
|
||||||
|
|
||||||
// If a Group was found, execute the query. If not, do nothing.
|
// If a Group was found or running in the context of a Personal tab, execute the query. If not, do nothing.
|
||||||
if(this.state.groupId) {
|
if(this.state.groupId || this.state.tabType == TabType.PersonalTab) {
|
||||||
|
|
||||||
this.props.context.msGraphClientFactory
|
this.props.context.msGraphClientFactory
|
||||||
.getClient()
|
.getClient()
|
||||||
.then((client: MSGraphClient): void => {
|
.then((client: MSGraphClient): void => {
|
||||||
|
|
||||||
|
let apiUrl: string = `/groups/${this.state.groupId}/events`;
|
||||||
|
if(this._isPersonalTab()) {
|
||||||
|
apiUrl = '/me/events';
|
||||||
|
}
|
||||||
|
|
||||||
client
|
client
|
||||||
.api(`/groups/${this.state.groupId}/events`)
|
.api(apiUrl)
|
||||||
.version("v1.0")
|
.version("v1.0")
|
||||||
.select('subject,start,end,location,bodyPreview,isAllDay')
|
.select('subject,start,end,location,bodyPreview,isAllDay')
|
||||||
.filter(`start/dateTime ge '${startDate.toISOString()}' and end/dateTime le '${endDate.toISOString()}'`)
|
.filter(`start/dateTime ge '${startDate.toISOString()}' and end/dateTime le '${endDate.toISOString()}'`)
|
||||||
|
|
Loading…
Reference in New Issue