Upgraded to SPFx1.7 (#678)
This commit is contained in:
parent
f1359c18cc
commit
2782b8ca98
|
@ -1,2 +0,0 @@
|
|||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
|
@ -1,11 +1,12 @@
|
|||
{
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"version": "1.5.0",
|
||||
"isCreatingSolution": true,
|
||||
"environment": "spo",
|
||||
"version": "1.7.0",
|
||||
"libraryName": "react-calendar-feed",
|
||||
"libraryId": "dd42aa00-b07d-48a2-8896-cc2f8c0d3fae",
|
||||
"environment": "spo",
|
||||
"isCreatingSolution": true,
|
||||
"packageManager": "npm",
|
||||
"isDomainIsolated": false,
|
||||
"componentType": "webpart"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ For more information about how this solution was built, including some design de
|
|||
|
||||
## Used SharePoint Framework Version
|
||||
|
||||
![SPFx v1.5](https://img.shields.io/badge/SPFx-1.5-green.svg)
|
||||
![SPFx v1.7](https://img.shields.io/badge/SPFx-1.7-green.svg)
|
||||
|
||||
## Applies to
|
||||
|
||||
|
@ -47,6 +47,7 @@ Version|Date|Comments
|
|||
-------|----|--------
|
||||
1.0|May 15, 2018|Initial release
|
||||
2.0|June 25, 2018|Converted to SPFx 1.5 and added Exchange Public Calendar support
|
||||
3.0|November 9, 2018|Converted to SPFx 1.7; Added SharePoint Calendar feed
|
||||
|
||||
## Disclaimer
|
||||
|
||||
|
@ -63,7 +64,7 @@ Version|Date|Comments
|
|||
- Insert the web part on a page
|
||||
- When prompted to configure the web part, select **Configure** to launch the web part property pane.
|
||||
- Select a feed type (RSS, iCal, WordPress, or Mock if using the debug solution)
|
||||
- Provide the feed's URL. If using _Mock_, provide any valid URL.
|
||||
- Provide the feed's URL. If using _Mock_, provide any valid URL (value will be ignored). If you wish to use a SharePoint calendar feed, provide the URL to the list (e.g.: https://yourtenant.sharepoint.com/sites/sitename/lists/eventlistname)
|
||||
- Specify a date range (one week, two weeks, one month, one quarter, one year)
|
||||
- Specify a maximum number of events to retrieve
|
||||
- If necessary, specify to use a proxy. Use this option if you encounter issues where your feed provider does not accept your tenant URL as a CORS origin.
|
||||
|
@ -81,5 +82,6 @@ This Web Part illustrates the following concepts on top of the SharePoint Framew
|
|||
- Creating shared components and services
|
||||
- Creating extensible services
|
||||
- Using a proxy to resolve CORS issues
|
||||
- Retrieving SharePoint events from a list with a filter
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-calendar-feed" />
|
||||
|
|
|
@ -17,4 +17,4 @@
|
|||
"ControlStrings": "node_modules/@pnp/spfx-controls-react/lib/loc/{locale}.js",
|
||||
"PropertyControlStrings": "node_modules/@pnp/spfx-property-controls/lib/loc/{locale}.js"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
{
|
||||
"$schema": "https://dev.office.com/json-schemas/spfx-build/copy-assets.schema.json",
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json",
|
||||
"deployCdnPath": "temp/deploy"
|
||||
}
|
||||
|
|
|
@ -3,8 +3,10 @@
|
|||
"solution": {
|
||||
"name": "react-calendar-feed-client-side-solution",
|
||||
"id": "dd42aa00-b07d-48a2-8896-cc2f8c0d3fae",
|
||||
"version": "1.0.1.2",
|
||||
"includeClientSideAssets": true
|
||||
"version": "3.0.0.0",
|
||||
"includeClientSideAssets": true,
|
||||
"isDomainIsolated": false,
|
||||
"iconPath": "images/appicon.png"
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/react-calendar-feed.sppkg"
|
||||
|
|
|
@ -1,45 +0,0 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/core-build/tslint.schema.json",
|
||||
// Display errors as warnings
|
||||
"displayAsWarning": true,
|
||||
// The TSLint task may have been configured with several custom lint rules
|
||||
// before this config file is read (for example lint rules from the tslint-microsoft-contrib
|
||||
// project). If true, this flag will deactivate any of these rules.
|
||||
"removeExistingRules": true,
|
||||
// When true, the TSLint task is configured with some default TSLint "rules.":
|
||||
"useDefaultConfigAsBase": false,
|
||||
// Since removeExistingRules=true and useDefaultConfigAsBase=false, there will be no lint rules
|
||||
// which are active, other than the list of rules below.
|
||||
"lintConfig": {
|
||||
// Opt-in to Lint rules which help to eliminate bugs in JavaScript
|
||||
"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-case": true,
|
||||
"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,
|
||||
"valid-typeof": true,
|
||||
"variable-name": false,
|
||||
"whitespace": false
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "react-calendar-feed",
|
||||
"version": "1.1.0",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
|
@ -11,34 +11,35 @@
|
|||
"test": "gulp test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft/sp-core-library": "~1.4.1",
|
||||
"@microsoft/sp-lodash-subset": "~1.4.1",
|
||||
"@microsoft/sp-office-ui-fabric-core": "~1.4.1",
|
||||
"@microsoft/sp-webpart-base": "~1.4.1",
|
||||
"@pnp/spfx-controls-react": "^1.3.0",
|
||||
"@pnp/spfx-property-controls": "^1.6.0",
|
||||
"@microsoft/sp-core-library": "1.7.0",
|
||||
"@microsoft/sp-lodash-subset": "1.7.0",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.7.0",
|
||||
"@microsoft/sp-webpart-base": "1.7.0",
|
||||
"@pnp/pnpjs": "^1.2.5",
|
||||
"@pnp/spfx-controls-react": "^1.10.0",
|
||||
"@pnp/spfx-property-controls": "^1.11.0",
|
||||
"@types/es6-promise": "0.0.33",
|
||||
"@types/react": "15.6.6",
|
||||
"@types/react-dom": "15.5.6",
|
||||
"@types/webpack-env": ">=1.12.1 <1.14.0",
|
||||
"ical.js": "^1.2.2",
|
||||
"@types/react": "16.4.2",
|
||||
"@types/react-dom": "16.0.5",
|
||||
"@types/webpack-env": "1.13.1",
|
||||
"ical.js": "^1.3.0",
|
||||
"ics-js": "^0.10.2",
|
||||
"jquery": "^3.3.1",
|
||||
"moment": "^2.22.1",
|
||||
"react": "15.6.2",
|
||||
"react-dom": "15.6.2",
|
||||
"react-slick": "^0.23.1",
|
||||
"moment": "^2.22.2",
|
||||
"react": "16.3.2",
|
||||
"react-dom": "16.3.2",
|
||||
"react-slick": "^0.23.2",
|
||||
"slick-carousel": "^1.8.1",
|
||||
"xml-js": "^1.6.2",
|
||||
"xml-js": "^1.6.8",
|
||||
"xml2js": "^0.4.19"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/sp-build-web": "~1.4.1",
|
||||
"@microsoft/sp-module-interfaces": "~1.4.1",
|
||||
"@microsoft/sp-webpart-workbench": "~1.4.1",
|
||||
"@types/chai": ">=3.4.34 <3.6.0",
|
||||
"@types/mocha": ">=2.2.33 <2.6.0",
|
||||
"ajv": "~5.2.2",
|
||||
"gulp": "~3.9.1"
|
||||
"@microsoft/sp-build-web": "1.7.0",
|
||||
"@microsoft/sp-tslint-rules": "1.7.0",
|
||||
"@microsoft/sp-module-interfaces": "1.7.0",
|
||||
"@microsoft/sp-webpart-workbench": "1.7.0",
|
||||
"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
|
|
@ -1,82 +1,88 @@
|
|||
import { css } from '@uifabric/utilities/lib/css';
|
||||
import { IconButton } from 'office-ui-fabric-react/lib/Button';
|
||||
import * as React from 'react';
|
||||
import Slider from 'react-slick';
|
||||
import { ICarouselContainerProps, ICarouselContainerState } from '.';
|
||||
import styles from './CarouselContainer.module.scss';
|
||||
import { css } from "@uifabric/utilities/lib/css";
|
||||
import { IconButton } from "office-ui-fabric-react/lib/Button";
|
||||
import * as React from "react";
|
||||
import Slider from "react-slick";
|
||||
import { ICarouselContainerProps, ICarouselContainerState } from ".";
|
||||
import styles from "./CarouselContainer.module.scss";
|
||||
|
||||
/**
|
||||
* Carousel container
|
||||
* Presents the child compoments as a slick slide
|
||||
*/
|
||||
export class CarouselContainer extends React.Component<ICarouselContainerProps, ICarouselContainerState> {
|
||||
// the slick slider used in normal views
|
||||
private _slider: Slider;
|
||||
export class CarouselContainer extends React.Component<
|
||||
ICarouselContainerProps,
|
||||
ICarouselContainerState
|
||||
> {
|
||||
// the slick slider used in normal views
|
||||
private _slider: Slider;
|
||||
|
||||
/**
|
||||
* Renders a slick switch, a slide for each child, and next/previous arrows
|
||||
*/
|
||||
public render(): React.ReactElement<ICarouselContainerProps> {
|
||||
var settings: any = {
|
||||
accessibility: true,
|
||||
arrows: false,
|
||||
autoplaySpeed: 5000,
|
||||
dots: true,
|
||||
infinite: true,
|
||||
slidesToShow: 4,
|
||||
slidesToScroll: 4,
|
||||
speed: 500,
|
||||
centerPadding: "50px",
|
||||
pauseOnHover: true,
|
||||
variableWidth: false,
|
||||
useCSS: true,
|
||||
rows: 1,
|
||||
respondTo: 'slider',
|
||||
responsive: [
|
||||
|
||||
{
|
||||
breakpoint: 2560,
|
||||
settings: {
|
||||
slidesToShow: 3,
|
||||
slidesToScroll: 3,
|
||||
}
|
||||
},
|
||||
{
|
||||
breakpoint: 801,
|
||||
settings: {
|
||||
slidesToShow: 2,
|
||||
slidesToScroll: 2,
|
||||
}
|
||||
},
|
||||
// there is no 1 slide option, as it converts to narrow view
|
||||
]
|
||||
};
|
||||
/**
|
||||
* Renders a slick switch, a slide for each child, and next/previous arrows
|
||||
*/
|
||||
public render(): React.ReactElement<ICarouselContainerProps> {
|
||||
// slick seems to have an issue with having "infinite" mode set to true and having less items than the number of slides per page
|
||||
// set infinite to true only if there are more than 3 children
|
||||
var isInfinite: boolean = React.Children.count(this.props.children) > 3;
|
||||
var settings: any = {
|
||||
accessibility: true,
|
||||
arrows: false,
|
||||
autoplaySpeed: 5000,
|
||||
dots: true,
|
||||
infinite: isInfinite,
|
||||
slidesToShow: 4,
|
||||
slidesToScroll: 4,
|
||||
speed: 500,
|
||||
centerPadding: "50px",
|
||||
pauseOnHover: true,
|
||||
variableWidth: false,
|
||||
useCSS: true,
|
||||
rows: 1,
|
||||
respondTo: "slider",
|
||||
responsive: [
|
||||
{
|
||||
breakpoint: 2560,
|
||||
settings: {
|
||||
slidesToShow: 3,
|
||||
slidesToScroll: 3
|
||||
}
|
||||
},
|
||||
{
|
||||
breakpoint: 801,
|
||||
settings: {
|
||||
slidesToShow: 2,
|
||||
slidesToScroll: 2
|
||||
}
|
||||
}
|
||||
// there is no 1 slide option, as it converts to narrow view
|
||||
]
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={css(styles.carouselContainer, styles.filmStrip)}>
|
||||
<Slider ref={c => (this._slider = c)}
|
||||
{...settings}>
|
||||
{this.props.children}
|
||||
</Slider>
|
||||
<div
|
||||
className={css(styles.indexButtonContainer, styles.sliderButtons)}
|
||||
style={{ "left": "10px" }}
|
||||
onClick={() => this._slider.slickPrev()}
|
||||
>
|
||||
<IconButton className={css(styles.indexButton, styles.leftPositioned)}
|
||||
iconProps={{ iconName: "ChevronLeft" }}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={css(styles.indexButtonContainer, styles.sliderButtons)}
|
||||
style={{ "right": "10px" }}
|
||||
onClick={() => this._slider.slickNext()}
|
||||
>
|
||||
<IconButton className={css(styles.indexButton, styles.rightPositioned)}
|
||||
iconProps={{ iconName: "ChevronRight" }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<div className={css(styles.carouselContainer, styles.filmStrip)}>
|
||||
<Slider ref={c => (this._slider = c)} {...settings}>
|
||||
{this.props.children}
|
||||
</Slider>
|
||||
<div
|
||||
className={css(styles.indexButtonContainer, styles.sliderButtons)}
|
||||
style={{ left: "10px" }}
|
||||
onClick={() => this._slider.slickPrev()}
|
||||
>
|
||||
<IconButton
|
||||
className={css(styles.indexButton, styles.leftPositioned)}
|
||||
iconProps={{ iconName: "ChevronLeft" }}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={css(styles.indexButtonContainer, styles.sliderButtons)}
|
||||
style={{ right: "10px" }}
|
||||
onClick={() => this._slider.slickNext()}
|
||||
>
|
||||
<IconButton
|
||||
className={css(styles.indexButton, styles.rightPositioned)}
|
||||
iconProps={{ iconName: "ChevronRight" }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
export * from './CarouselContainer';
|
||||
export * from './CarouselContainer.types';
|
||||
export * from "./CarouselContainer";
|
||||
export * from "./CarouselContainer.types";
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
import * as moment from 'moment';
|
||||
import { css } from 'office-ui-fabric-react/lib/Utilities';
|
||||
import * as React from 'react';
|
||||
import styles from './DateBox.module.scss';
|
||||
import { DateBoxSize, IDateBoxProps, IDateBoxState } from './DateBox.types';
|
||||
import * as moment from "moment";
|
||||
import { css } from "office-ui-fabric-react/lib/Utilities";
|
||||
import * as React from "react";
|
||||
import styles from "./DateBox.module.scss";
|
||||
import { DateBoxSize, IDateBoxProps, IDateBoxState } from "./DateBox.types";
|
||||
|
||||
/**
|
||||
* Shows a date in a SharePoint-looking date
|
||||
|
@ -50,4 +50,4 @@ export class DateBox extends React.Component<IDateBoxProps, IDateBoxState> {
|
|||
<div className={styles.date} data-automation-id="multipleDayEndDateContainer">{endMoment.format("MMM D").toUpperCase()}</div>
|
||||
</div>);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
export * from './DateBox';
|
||||
export * from './DateBox.types';
|
||||
export * from "./DateBox";
|
||||
export * from "./DateBox.types";
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
import { Guid } from '@microsoft/sp-core-library';
|
||||
import * as strings from 'CalendarFeedSummaryWebPartStrings';
|
||||
import * as ICS from 'ics-js';
|
||||
import * as moment from 'moment';
|
||||
import { ActionButton, DocumentCard, DocumentCardType, FocusZone, css } from 'office-ui-fabric-react';
|
||||
import * as React from 'react';
|
||||
import { IEventCardProps, IEventCardState } from '.';
|
||||
import { DateBox, DateBoxSize } from '../DateBox';
|
||||
import styles from './EventCard.module.scss';
|
||||
const AllDayFormat: string = 'dddd, MMMM Do YYYY';
|
||||
const LocalizedTimeFormat: string = 'llll';
|
||||
import { Text } from '@microsoft/sp-core-library';
|
||||
import { Guid } from "@microsoft/sp-core-library";
|
||||
import * as strings from "CalendarFeedSummaryWebPartStrings";
|
||||
import * as ICS from "ics-js";
|
||||
import * as moment from "moment";
|
||||
import { ActionButton, DocumentCard, DocumentCardType, FocusZone, css } from "office-ui-fabric-react";
|
||||
import * as React from "react";
|
||||
import { IEventCardProps, IEventCardState } from ".";
|
||||
import { DateBox, DateBoxSize } from "../DateBox";
|
||||
import styles from "./EventCard.module.scss";
|
||||
import { Text } from "@microsoft/sp-core-library";
|
||||
/**
|
||||
* Shows an event in a document card
|
||||
*/
|
||||
|
@ -31,10 +29,10 @@ export class EventCard extends React.Component<IEventCardProps, IEventCardState>
|
|||
title,
|
||||
url,
|
||||
category,
|
||||
description,
|
||||
// description,
|
||||
location } = this.props.event;
|
||||
const eventDate: moment.Moment = moment(start);
|
||||
const dateString: string = allDay ? eventDate.format(AllDayFormat) : eventDate.format(LocalizedTimeFormat);
|
||||
const dateString: string = allDay ? eventDate.format(strings.AllDayDateFormat) : eventDate.format(strings.LocalizedTimeFormat);
|
||||
const { isEditMode } = this.props;
|
||||
return (
|
||||
<div>
|
||||
|
@ -87,10 +85,11 @@ export class EventCard extends React.Component<IEventCardProps, IEventCardState>
|
|||
allDay,
|
||||
title,
|
||||
url,
|
||||
category,
|
||||
location } = this.props.event;
|
||||
// category,
|
||||
// location
|
||||
} = this.props.event;
|
||||
const eventDate: moment.Moment = moment.utc(start);
|
||||
const dateString: string = allDay ? eventDate.format(AllDayFormat) : eventDate.format(LocalizedTimeFormat);
|
||||
const dateString: string = allDay ? eventDate.format(strings.AllDayDateFormat) : eventDate.format(strings.LocalizedTimeFormat);
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { ICalendarEvent } from '../../../../lib/shared/services/CalendarService';
|
||||
import { ICalendarEvent } from "../../../shared/services/CalendarService";
|
||||
|
||||
export interface IEventCardProps {
|
||||
isEditMode: boolean;
|
||||
|
@ -6,4 +6,4 @@ export interface IEventCardProps {
|
|||
isNarrow: boolean;
|
||||
}
|
||||
|
||||
export interface IEventCardState {}
|
||||
export interface IEventCardState {}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
export * from './EventCard';
|
||||
export * from './EventCard.types';
|
||||
export * from "./EventCard";
|
||||
export * from "./EventCard.types";
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import { ActionButton, IButtonProps } from 'office-ui-fabric-react/lib/Button';
|
||||
import { Icon } from 'office-ui-fabric-react/lib/Icon';
|
||||
import { css } from 'office-ui-fabric-react/lib/Utilities';
|
||||
import * as React from 'react';
|
||||
import { IPagingProps, IPagingState } from '.';
|
||||
import styles from './Paging.module.scss';
|
||||
import * as strings from 'CalendarFeedSummaryWebPartStrings';
|
||||
import { ActionButton, IButtonProps } from "office-ui-fabric-react/lib/Button";
|
||||
import { Icon } from "office-ui-fabric-react/lib/Icon";
|
||||
import { css } from "office-ui-fabric-react/lib/Utilities";
|
||||
import * as React from "react";
|
||||
import { IPagingProps, IPagingState } from ".";
|
||||
import styles from "./Paging.module.scss";
|
||||
import * as strings from "CalendarFeedSummaryWebPartStrings";
|
||||
|
||||
/**
|
||||
* A custom pagination control designed to look & feel like Office UI Fabric
|
||||
|
@ -12,7 +12,7 @@ import * as strings from 'CalendarFeedSummaryWebPartStrings';
|
|||
export class Paging extends React.Component<IPagingProps, IPagingState> {
|
||||
public render(): React.ReactElement<IPagingProps> {
|
||||
|
||||
const { totalItems, itemsCountPerPage, currentPage } = this.props;
|
||||
const { currentPage } = this.props;
|
||||
|
||||
// calculate the page situation
|
||||
const numberOfPages: number = this._getNumberOfPages();
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
export * from './Paging';
|
||||
export * from './Paging.types';
|
||||
export * from "./Paging";
|
||||
export * from "./Paging.types";
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { HttpClient, HttpClientResponse } from '@microsoft/sp-http';
|
||||
import { IWebPartContext } from '@microsoft/sp-webpart-base';
|
||||
import * as moment from 'moment';
|
||||
import { CalendarEventRange } from '.';
|
||||
import { ICalendarEvent } from './ICalendarEvent';
|
||||
import { ICalendarService } from './ICalendarService';
|
||||
import { HttpClient, HttpClientResponse } from "@microsoft/sp-http";
|
||||
import { IWebPartContext } from "@microsoft/sp-webpart-base";
|
||||
import * as moment from "moment";
|
||||
import { CalendarEventRange } from ".";
|
||||
import { ICalendarEvent } from "./ICalendarEvent";
|
||||
import { ICalendarService } from "./ICalendarService";
|
||||
|
||||
/**
|
||||
* Base Calendar Service
|
||||
|
@ -60,7 +60,6 @@ export abstract class BaseCalendarService implements ICalendarService {
|
|||
*/
|
||||
protected replaceTokens(feedUrl: string, dateRange: CalendarEventRange): string {
|
||||
const startMoment: moment.Moment = moment(dateRange.Start);
|
||||
const endMoment: moment.Moment = moment(dateRange.End);
|
||||
const startDate: string = startMoment.format("YYYY-MM-DD");
|
||||
const endDate: string = startMoment.format("YYYY-MM-DD");
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import * as moment from 'moment';
|
||||
import * as moment from "moment";
|
||||
|
||||
export enum DateRange {
|
||||
OneWeek,
|
||||
|
|
|
@ -1,53 +1,61 @@
|
|||
import { MockCalendarService } from './MockCalendarService';
|
||||
import { RSSCalendarService } from './RSSCalendarService';
|
||||
import { WordPressFullCalendarService } from './WordPressFullCalendarService';
|
||||
import { iCalCalendarService } from './iCalCalendarService';
|
||||
import { ExchangePublicCalendarService } from './ExchangePublicCalendarService';
|
||||
import { MockCalendarService } from "./MockCalendarService";
|
||||
import { RSSCalendarService } from "./RSSCalendarService";
|
||||
import { WordPressFullCalendarService } from "./WordPressFullCalendarService";
|
||||
import { iCalCalendarService } from "./iCalCalendarService";
|
||||
import { ExchangePublicCalendarService } from "./ExchangePublicCalendarService";
|
||||
import { SharePointCalendarService } from "./SharePointCalendarService";
|
||||
|
||||
export class CalendarServiceProviderList {
|
||||
public static getProviders(): any[] {
|
||||
const providers: any[] = [];
|
||||
public static getProviders(): any[] {
|
||||
const providers: any[] = [];
|
||||
|
||||
// only include the Mock service provider in DEBUG
|
||||
if (DEBUG) {
|
||||
providers.push({
|
||||
label: "Mock",
|
||||
key: "mock",
|
||||
initialize: () => new MockCalendarService()
|
||||
});
|
||||
}
|
||||
|
||||
providers.push({
|
||||
label: "Exchange Public Calendar",
|
||||
key: "exchange",
|
||||
initialize: () => new ExchangePublicCalendarService()
|
||||
});
|
||||
|
||||
providers.push({
|
||||
label: "WordPress",
|
||||
key: "wordpress",
|
||||
initialize: () => new WordPressFullCalendarService()
|
||||
});
|
||||
|
||||
providers.push({
|
||||
label: "iCal",
|
||||
key: "ical",
|
||||
initialize: () => new iCalCalendarService()
|
||||
});
|
||||
|
||||
providers.push({
|
||||
label: "RSS",
|
||||
key: "RSS",
|
||||
initialize: () => new RSSCalendarService()
|
||||
});
|
||||
|
||||
return providers;
|
||||
// only include the Mock service provider in DEBUG
|
||||
if (DEBUG) {
|
||||
providers.push({
|
||||
label: "Mock",
|
||||
key: "mock",
|
||||
initialize: () => new MockCalendarService()
|
||||
});
|
||||
}
|
||||
|
||||
providers.push({
|
||||
label: "SharePoint Calendar",
|
||||
key: "sharepoint",
|
||||
initialize: () => new SharePointCalendarService()
|
||||
});
|
||||
|
||||
providers.push({
|
||||
label: "Exchange Public Calendar",
|
||||
key: "exchange",
|
||||
initialize: () => new ExchangePublicCalendarService()
|
||||
});
|
||||
|
||||
providers.push({
|
||||
label: "WordPress",
|
||||
key: "wordpress",
|
||||
initialize: () => new WordPressFullCalendarService()
|
||||
});
|
||||
|
||||
providers.push({
|
||||
label: "iCal",
|
||||
key: "ical",
|
||||
initialize: () => new iCalCalendarService()
|
||||
});
|
||||
|
||||
providers.push({
|
||||
label: "RSS",
|
||||
key: "RSS",
|
||||
initialize: () => new RSSCalendarService()
|
||||
});
|
||||
|
||||
return providers;
|
||||
}
|
||||
}
|
||||
|
||||
export enum CalendarServiceProviderType {
|
||||
WordPress = "WordPress",
|
||||
iCal = "iCal",
|
||||
RSS = "RSS",
|
||||
Mock = "Mock"
|
||||
}
|
||||
SharePoint = "SharePoint",
|
||||
WordPress = "WordPress",
|
||||
iCal = "iCal",
|
||||
RSS = "RSS",
|
||||
Mock = "Mock"
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
/**
|
||||
* Exchange Public Calendar Service
|
||||
*/
|
||||
import { ICalendarService } from '..';
|
||||
import { ICalendarEvent } from '../ICalendarEvent';
|
||||
import { iCalCalendarService } from '../iCalCalendarService';
|
||||
import { ICalendarService } from "..";
|
||||
import { ICalendarEvent } from "../ICalendarEvent";
|
||||
import { iCalCalendarService } from "../iCalCalendarService";
|
||||
|
||||
// tslint:disable-next-line:class-name
|
||||
export class ExchangePublicCalendarService extends iCalCalendarService implements ICalendarService {
|
||||
|
@ -13,8 +13,8 @@ export class ExchangePublicCalendarService extends iCalCalendarService implement
|
|||
}
|
||||
|
||||
public getEvents = (): Promise<ICalendarEvent[]> => {
|
||||
// Exchange public calendar shares are really ICS calendars.
|
||||
// we allow users to pass either the .html URL or
|
||||
// exchange public calendar shares are really ICS calendars.
|
||||
// we allow users to pass either the .html URL or
|
||||
// the .ics, but we really need the .ics file
|
||||
|
||||
const htmlExtension:string = ".html";
|
||||
|
@ -25,15 +25,5 @@ export class ExchangePublicCalendarService extends iCalCalendarService implement
|
|||
}
|
||||
|
||||
return this.getEvents();
|
||||
}
|
||||
|
||||
private changeExtensionToIcs(url: string): string {
|
||||
const htmlExtension:string = ".html";
|
||||
if (url.indexOf(htmlExtension, url.length - htmlExtension.length) >= 0) {
|
||||
// the url ends with .html. Replace it with .ics
|
||||
const root: string = url.substring(0, url.length - htmlExtension.length);
|
||||
return `${root}.ics`;
|
||||
}
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
export * from './ExchangePublicCalendarService';
|
||||
export * from "./ExchangePublicCalendarService";
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import { IWebPartContext } from '@microsoft/sp-webpart-base';
|
||||
import { CalendarEventRange, ICalendarEvent } from '.';
|
||||
import { IWebPartContext } from "@microsoft/sp-webpart-base";
|
||||
import { CalendarEventRange, ICalendarEvent } from ".";
|
||||
|
||||
export interface ICalendarService {
|
||||
Context: IWebPartContext;
|
||||
|
@ -9,4 +9,4 @@ export interface ICalendarService {
|
|||
CacheDuration: number;
|
||||
Name: string;
|
||||
getEvents: () => Promise<ICalendarEvent[]>;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,12 +3,11 @@
|
|||
* This provider will NOT be listed in the list of available providers when this solution is packaged with --ship.
|
||||
* Don't freak out, it didn't just disappear.
|
||||
*/
|
||||
import * as moment from 'moment';
|
||||
import { BaseCalendarService } from '../BaseCalendarService';
|
||||
import { ICalendarEvent } from '../ICalendarEvent';
|
||||
import { ICalendarService } from '../ICalendarService';
|
||||
import * as moment from "moment";
|
||||
import { BaseCalendarService } from "../BaseCalendarService";
|
||||
import { ICalendarEvent } from "../ICalendarEvent";
|
||||
import { ICalendarService } from "../ICalendarService";
|
||||
|
||||
const today: Date = new Date();
|
||||
const sampleEvents: ICalendarEvent[] = [
|
||||
{
|
||||
"title": "This event will be tomorrow",
|
||||
|
@ -155,4 +154,4 @@ export class MockCalendarService extends BaseCalendarService implements ICalenda
|
|||
}, 1000);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
export * from './MockCalendarService';
|
||||
export * from "./MockCalendarService";
|
||||
|
|
|
@ -6,12 +6,12 @@
|
|||
* every one I could find on NPM and GitHub and found that they did not meet my needs.
|
||||
* I'm open to suggestions, though, if you have a library that you think would work better.
|
||||
*/
|
||||
import { HttpClientResponse } from '@microsoft/sp-http';
|
||||
import * as convert from 'xml-js';
|
||||
import { ICalendarService } from '..';
|
||||
import { BaseCalendarService } from '../BaseCalendarService';
|
||||
import { ICalendarEvent } from '../ICalendarEvent';
|
||||
import { escape, unescape } from '@microsoft/sp-lodash-subset';
|
||||
import { HttpClientResponse } from "@microsoft/sp-http";
|
||||
import * as convert from "xml-js";
|
||||
import { ICalendarService } from "..";
|
||||
import { BaseCalendarService } from "../BaseCalendarService";
|
||||
import { ICalendarEvent } from "../ICalendarEvent";
|
||||
import { unescape } from "@microsoft/sp-lodash-subset";
|
||||
|
||||
export class RSSCalendarService extends BaseCalendarService implements ICalendarService {
|
||||
constructor() {
|
||||
|
@ -51,7 +51,6 @@ export class RSSCalendarService extends BaseCalendarService implements ICalendar
|
|||
let title: string = this._getElementValue(item, "title");
|
||||
let link: string = this._getElementValue(item, "link");
|
||||
let pubDate: Date = new Date(this._getElementValue(item, "pubDate"));
|
||||
let category: string = this._getElementValue(item, "category");
|
||||
let description: string = this._getElementValue(item, "description");
|
||||
return {
|
||||
title: title,
|
||||
|
@ -100,4 +99,4 @@ export class RSSCalendarService extends BaseCalendarService implements ICalendar
|
|||
console.log("Found an RSS field type I didn't know", firstElement.type);
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
export * from './RSSCalendarService';
|
||||
export * from "./RSSCalendarService";
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
* ExtensionService
|
||||
*/
|
||||
import { HttpClientResponse } from "@microsoft/sp-http";
|
||||
import { ICalendarService } from "..";
|
||||
import { BaseCalendarService } from "../BaseCalendarService";
|
||||
import { ICalendarEvent } from "../ICalendarEvent";
|
||||
import { Web, sp } from "@pnp/sp";
|
||||
import { combine } from "@pnp/common";
|
||||
|
||||
export class SharePointCalendarService extends BaseCalendarService
|
||||
implements ICalendarService {
|
||||
constructor() {
|
||||
super();
|
||||
this.Name = "SharePoint";
|
||||
}
|
||||
|
||||
public getEvents = (): Promise<ICalendarEvent[]> => {
|
||||
const parameterizedFeedUrl: string = this.replaceTokens(
|
||||
this.FeedUrl,
|
||||
this.EventRange
|
||||
);
|
||||
|
||||
// Get the URL
|
||||
let webUrl = this.FeedUrl.toLowerCase();
|
||||
|
||||
// Break the URL into parts
|
||||
let urlParts = webUrl.split("/");
|
||||
|
||||
// Get the web root
|
||||
let webRoot = urlParts[0] + "/" + urlParts[1] + "/" + urlParts[2];
|
||||
|
||||
// Get the list URL
|
||||
let listUrl = webUrl.substring(webRoot.length);
|
||||
|
||||
// Find the "lists" portion of the URL to get the site URL
|
||||
let webLocation = listUrl.substr(0, listUrl.indexOf("lists/"));
|
||||
let siteUrl = webRoot + webLocation;
|
||||
|
||||
// Open the web associated to the site
|
||||
let web = new Web(siteUrl);
|
||||
|
||||
// Get the web
|
||||
return web.get().then(() => {
|
||||
// Build a filter so that we don't retrieve every single thing unless necesssary
|
||||
let dateFilter:string = "EventDate ge datetime'"+this.EventRange.Start.toISOString()+"' and EndDate lt datetime'"+this.EventRange.End.toISOString()+"'";
|
||||
|
||||
// When we receive the web, get the list
|
||||
return web
|
||||
.getList(listUrl)
|
||||
.items.select("Id,Title,Description,EventDate,EndDate,fAllDayEvent,Category,Location")
|
||||
.filter(dateFilter)
|
||||
.getAll()
|
||||
.then((items: any[]) => {
|
||||
// Once we get the list, convert to calendar events
|
||||
let events: ICalendarEvent[] = items.map((item: any) => {
|
||||
let eventUrl:string = combine(webUrl, "DispForm.aspx?ID="+item.Id);
|
||||
return {
|
||||
title: item.Title,
|
||||
start: item.EventDate,
|
||||
end: item.EndDate,
|
||||
url: eventUrl,
|
||||
allDay: item.fAllDayEvent,
|
||||
category: item.Category,
|
||||
description: item.Description,
|
||||
location: item.Location
|
||||
};
|
||||
});
|
||||
|
||||
// Return the calendar items
|
||||
return events;
|
||||
})
|
||||
.catch((error: any) => {
|
||||
console.log(
|
||||
"Exception caught by catch in SharePoint provider",
|
||||
error
|
||||
);
|
||||
throw error;
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
export * from "./SharePointCalendarService";
|
|
@ -1,10 +1,10 @@
|
|||
/**
|
||||
* ExtensionService
|
||||
*/
|
||||
import { ICalendarService } from '..';
|
||||
import { BaseCalendarService } from '../BaseCalendarService';
|
||||
import { ICalendarEvent } from '../ICalendarEvent';
|
||||
import { IWordPressFullCalendarEventResponse } from './IWordPressFullCalendarEventResponse';
|
||||
import { ICalendarService } from "..";
|
||||
import { BaseCalendarService } from "../BaseCalendarService";
|
||||
import { ICalendarEvent } from "../ICalendarEvent";
|
||||
import { IWordPressFullCalendarEventResponse } from "./IWordPressFullCalendarEventResponse";
|
||||
|
||||
export class WordPressFullCalendarService extends BaseCalendarService implements ICalendarService {
|
||||
constructor() {
|
||||
|
@ -39,4 +39,4 @@ export class WordPressFullCalendarService extends BaseCalendarService implements
|
|||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
export * from './IWordPressFullCalendarEventResponse';
|
||||
export * from './WordPressFullCalendarService';
|
||||
export * from "./IWordPressFullCalendarEventResponse";
|
||||
export * from "./WordPressFullCalendarService";
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/**
|
||||
* ExtensionService
|
||||
*/
|
||||
import { HttpClientResponse } from '@microsoft/sp-http';
|
||||
import * as ICAL from 'ical.js';
|
||||
import { ICalendarService } from '..';
|
||||
import { BaseCalendarService } from '../BaseCalendarService';
|
||||
import { ICalendarEvent } from '../ICalendarEvent';
|
||||
import { HttpClientResponse } from "@microsoft/sp-http";
|
||||
import * as ICAL from "ical.js";
|
||||
import { ICalendarService } from "..";
|
||||
import { BaseCalendarService } from "../BaseCalendarService";
|
||||
import { ICalendarEvent } from "../ICalendarEvent";
|
||||
|
||||
// tslint:disable-next-line:class-name
|
||||
export class iCalCalendarService extends BaseCalendarService implements ICalendarService {
|
||||
|
@ -47,4 +47,4 @@ export class iCalCalendarService extends BaseCalendarService implements ICalenda
|
|||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1 @@
|
|||
export * from './iCalCalendarService';
|
||||
export * from "./iCalCalendarService";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
export * from './ICalendarEvent';
|
||||
export * from './ICalendarService';
|
||||
export * from './CalendarEventRange';
|
||||
export * from './CalendarServiceProviderList';
|
||||
export * from "./ICalendarEvent";
|
||||
export * from "./ICalendarService";
|
||||
export * from "./CalendarEventRange";
|
||||
export * from "./CalendarServiceProviderList";
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
|
@ -1,20 +1,15 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
|
||||
"id": "b83bb343-bc5e-460c-9efd-52de06d32ffa",
|
||||
"id": "0459b501-da31-43c7-9a9a-d5c59cc2d667",
|
||||
"alias": "CalendarFeedSummaryWebPart",
|
||||
"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,
|
||||
"preconfiguredEntries": [
|
||||
{
|
||||
"groupId": "cf066440-0614-43d6-98ae-0b31cf14c7c3", // Text, media and content
|
||||
|
||||
"preconfiguredEntries": [{
|
||||
"groupId": "cf066440-0614-43d6-98ae-0b31cf14c7c3",
|
||||
"group": {
|
||||
"default": "Text, media and content"
|
||||
},
|
||||
|
@ -24,16 +19,13 @@
|
|||
"description": {
|
||||
"default": "Shows a summary view of a list of calendar events retrieved from an external feed."
|
||||
},
|
||||
// commented out because of bug with base64 icons
|
||||
// "iconImageUrl": "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI0MCIgaGVpZ2h0PSIyOCIgdmlld0JveD0iMCAwIDEwLjU4IDcuNDEiPjxwYXRoIGQ9Ik0yLjQ4LS4wMVYuNUgxLjJ2Ni4xNWg1LjcyVjYuM0gxLjU0VjIuMmg2LjR2Mi44OGguMjVWLjVINi45MVYwaC0uMzZWLjVIMi44MlYwaC0uMTN6bS0uOTQuODVoLjk0di40M2guMzRWLjg0aDMuNzN2LjQzaC4zNlYuODRoMS4wM3YuOTRoLTYuNHYtLjQ3eiIvPjxwYXRoIGQ9Ik03LjIyIDUuNjh2LS40M2EyLjE2IDIuMTYgMCAwIDEgMi4xNyAyLjE3bC0uNDUtLjAxYy4wMi0uNy0uNDktMS43LTEuNzItMS43M3ptMCAuNzJ2LS40M2MuOTIuMDUgMS40My43IDEuNDQgMS40NWgtLjQzYy0uMDEtLjY2LS40NS0xLTEuMDEtMS4wMnptLjYuN2EuMy4zIDAgMCAxLS4zLjMuMy4zIDAgMCAxLS4zMS0uMy4zLjMgMCAwIDEgLjMtLjI5LjMuMyAwIDAgMSAuMy4zeiIvPjxwYXRoIGQ9Ik0yLjQ4LS4wMVYuNUgxLjJsLjAzIDIuMjMtLjAzIDMuOTJoNS43MlY2LjNIMS41NFYyLjJoNi40djIuODhoLjI1Vi41SDYuOTFWMGgtLjM2Vi41SDIuODJWMGgtLjEzem0tLjk0Ljg1aC45NHYuNDNoLjM0Vi44NGgzLjczdi40M2guMzZWLjg0aDEuMDN2Ljk0aC02LjR2LS40N3oiLz48cGF0aCBkPSJNMi41IDIuNzNoMS42OHYuMzZIMi41em00LjA3LjM2aC4zNHYyLjI4aC0uMzR6bS0xLjM3IDBoLjM1djIuMjhINS4yem0wIDIuMjhoMS43MXYuMzZoLTEuN3ptMC0yLjY0aDEuNzF2LjM2aC0xLjd6Ii8+PHBhdGggZD0iTTMuODYgMy4xaC4zNHYyLjI3aC0uMzR6bS0xLjM2IDBoLjM0djIuMjdIMi41em0wIDIuMjdoMS43di4zNkgyLjV6bTAtMi42NGgxLjd2LjM2SDIuNXoiLz48L3N2Zz4=",
|
||||
"officeFabricIconFontName": "Calendar",
|
||||
"properties": {
|
||||
"title": "Upcoming Events",
|
||||
"dateRange": 4, /* Year */
|
||||
"dateRange": 4,
|
||||
"maxEvents": 4,
|
||||
"useCORS": false,
|
||||
"cacheDuration": 15 /* 15 minutes */
|
||||
"cacheDuration": 15
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}]
|
||||
}
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
import { Version } from '@microsoft/sp-core-library';
|
||||
// tslint:disable-next-line:max-line-length
|
||||
import { BaseClientSideWebPart, IPropertyPaneConfiguration, IPropertyPaneDropdownOption, PropertyPaneDropdown } from '@microsoft/sp-webpart-base';
|
||||
import { CalloutTriggers } from '@pnp/spfx-property-controls/lib/PropertyFieldHeader';
|
||||
import { PropertyFieldNumber } from '@pnp/spfx-property-controls/lib/PropertyFieldNumber';
|
||||
import { PropertyFieldSliderWithCallout } from '@pnp/spfx-property-controls/lib/PropertyFieldSliderWithCallout';
|
||||
import { PropertyFieldTextWithCallout } from '@pnp/spfx-property-controls/lib/PropertyFieldTextWithCallout';
|
||||
import { PropertyFieldToggleWithCallout } from '@pnp/spfx-property-controls/lib/PropertyFieldToggleWithCallout';
|
||||
import * as strings from 'CalendarFeedSummaryWebPartStrings';
|
||||
import * as React from 'react';
|
||||
import * as ReactDom from 'react-dom';
|
||||
import { CalendarEventRange, DateRange, ICalendarService } from '../../shared/services/CalendarService';
|
||||
import { CalendarServiceProviderList } from '../../shared/services/CalendarService/CalendarServiceProviderList';
|
||||
import { ICalendarFeedSummaryWebPartProps } from './CalendarFeedSummaryWebPart.types';
|
||||
import CalendarFeedSummary from './components/CalendarFeedSummary';
|
||||
import { ICalendarFeedSummaryProps } from './components/CalendarFeedSummary.types';
|
||||
import { BaseClientSideWebPart, IPropertyPaneConfiguration, IPropertyPaneDropdownOption, PropertyPaneDropdown } from "@microsoft/sp-webpart-base";
|
||||
import { CalloutTriggers } from "@pnp/spfx-property-controls/lib/PropertyFieldHeader";
|
||||
import { PropertyFieldNumber } from "@pnp/spfx-property-controls/lib/PropertyFieldNumber";
|
||||
import { PropertyFieldSliderWithCallout } from "@pnp/spfx-property-controls/lib/PropertyFieldSliderWithCallout";
|
||||
import { PropertyFieldTextWithCallout } from "@pnp/spfx-property-controls/lib/PropertyFieldTextWithCallout";
|
||||
import { PropertyFieldToggleWithCallout } from "@pnp/spfx-property-controls/lib/PropertyFieldToggleWithCallout";
|
||||
import * as strings from "CalendarFeedSummaryWebPartStrings";
|
||||
import * as React from "react";
|
||||
import * as ReactDom from "react-dom";
|
||||
import { CalendarEventRange, DateRange, ICalendarService } from "../../shared/services/CalendarService";
|
||||
import { CalendarServiceProviderList } from "../../shared/services/CalendarService/CalendarServiceProviderList";
|
||||
import { ICalendarFeedSummaryWebPartProps } from "./CalendarFeedSummaryWebPart.types";
|
||||
import CalendarFeedSummary from "./components/CalendarFeedSummary";
|
||||
import { ICalendarFeedSummaryProps } from "./components/CalendarFeedSummary.types";
|
||||
|
||||
// this is the same width that the SharePoint events web parts use to render as narrow
|
||||
const MaxMobileWidth: number = 480;
|
||||
|
@ -39,7 +38,7 @@ export default class CalendarFeedSummaryWebPart extends BaseClientSideWebPart<IC
|
|||
*/
|
||||
public render(): void {
|
||||
// see if we need to render a mobile view
|
||||
const isNarrow: boolean = this.width <= MaxMobileWidth;
|
||||
const isNarrow: boolean = this.domElement.clientWidth <= MaxMobileWidth;
|
||||
|
||||
// display the summary (or the configuration screen)
|
||||
const element: React.ReactElement<ICalendarFeedSummaryProps> = React.createElement(
|
||||
|
@ -61,14 +60,6 @@ export default class CalendarFeedSummaryWebPart extends BaseClientSideWebPart<IC
|
|||
ReactDom.render(element, this.domElement);
|
||||
}
|
||||
|
||||
/**
|
||||
* We store our configure in version 1.0. If we ever change how we store our configuration information,
|
||||
* we'll update the version number here.
|
||||
*/
|
||||
protected get dataVersion(): Version {
|
||||
return Version.parse("1.0");
|
||||
}
|
||||
|
||||
/**
|
||||
* We're disabling reactive property panes here because we don't want the web part to try to update events as
|
||||
* people are typing in the feed URL.
|
||||
|
@ -231,7 +222,6 @@ export default class CalendarFeedSummaryWebPart extends BaseClientSideWebPart<IC
|
|||
*/
|
||||
private _getDataProvider(): ICalendarService {
|
||||
const {
|
||||
feedType,
|
||||
feedUrl,
|
||||
useCORS,
|
||||
cacheDuration
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { DateRange } from '../../shared/services/CalendarService';
|
||||
import { DateRange } from "../../shared/services/CalendarService";
|
||||
|
||||
/**
|
||||
* Web part properties stored in web part configuration
|
||||
|
@ -11,4 +11,4 @@ export interface ICalendarFeedSummaryWebPartProps {
|
|||
dateRange: DateRange; // date range to retrieve events
|
||||
useCORS: boolean; // use CORS proxy when retrieving events
|
||||
cacheDuration: number; // how long to cache events for
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
import { DisplayMode } from '@microsoft/sp-core-library';
|
||||
import { SPComponentLoader } from '@microsoft/sp-loader';
|
||||
import { Placeholder } from '@pnp/spfx-controls-react/lib/Placeholder';
|
||||
import { WebPartTitle } from '@pnp/spfx-controls-react/lib/WebPartTitle';
|
||||
import * as strings from 'CalendarFeedSummaryWebPartStrings';
|
||||
import * as moment from 'moment';
|
||||
import { FocusZone, FocusZoneDirection, List, Spinner, css } from 'office-ui-fabric-react';
|
||||
import * as React from 'react';
|
||||
import { CarouselContainer } from '../../../shared/components/CarouselContainer';
|
||||
import { EventCard } from '../../../shared/components/EventCard';
|
||||
import { Paging } from '../../../shared/components/Paging';
|
||||
import { CalendarServiceProviderType, ICalendarEvent, ICalendarService } from '../../../shared/services/CalendarService';
|
||||
import styles from './CalendarFeedSummary.module.scss';
|
||||
import { ICalendarFeedSummaryProps, ICalendarFeedSummaryState, IFeedCache } from './CalendarFeedSummary.types';
|
||||
import { DisplayMode } from "@microsoft/sp-core-library";
|
||||
import { SPComponentLoader } from "@microsoft/sp-loader";
|
||||
import { Placeholder } from "@pnp/spfx-controls-react/lib/Placeholder";
|
||||
import { WebPartTitle } from "@pnp/spfx-controls-react/lib/WebPartTitle";
|
||||
import * as strings from "CalendarFeedSummaryWebPartStrings";
|
||||
import * as moment from "moment";
|
||||
import { FocusZone, FocusZoneDirection, List, Spinner, css } from "office-ui-fabric-react";
|
||||
import * as React from "react";
|
||||
import { CarouselContainer } from "../../../shared/components/CarouselContainer";
|
||||
import { EventCard } from "../../../shared/components/EventCard";
|
||||
import { Paging } from "../../../shared/components/Paging";
|
||||
import { CalendarServiceProviderType, ICalendarEvent, ICalendarService } from "../../../shared/services/CalendarService";
|
||||
import styles from "./CalendarFeedSummary.module.scss";
|
||||
import { ICalendarFeedSummaryProps, ICalendarFeedSummaryState, IFeedCache } from "./CalendarFeedSummary.types";
|
||||
|
||||
// the key used when caching events
|
||||
const CacheKey: string = "calendarFeedSummary";
|
||||
|
@ -30,8 +30,8 @@ export default class CalendarFeedSummary extends React.Component<ICalendarFeedSu
|
|||
};
|
||||
|
||||
// needed for the slick slider in normal mode
|
||||
SPComponentLoader.loadCss("https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.css");
|
||||
SPComponentLoader.loadCss("https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick-theme.min.css");
|
||||
SPComponentLoader.loadCss("https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick.min.css");
|
||||
SPComponentLoader.loadCss("https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.8.1/slick-theme.min.css");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -69,8 +69,10 @@ export default class CalendarFeedSummary extends React.Component<ICalendarFeedSu
|
|||
}
|
||||
|
||||
const settingsHaveChanged: boolean = prevProvider.CacheDuration !== currProvider.CacheDuration ||
|
||||
prevProvider.Name !== currProvider.Name ||
|
||||
prevProvider.FeedUrl !== currProvider.FeedUrl ||
|
||||
prevProvider.Name !== currProvider.Name ||
|
||||
prevProvider.EventRange.DateRange !== currProvider.EventRange.DateRange ||
|
||||
prevProvider.UseCORS !== currProvider.UseCORS;
|
||||
|
||||
if (settingsHaveChanged) {
|
||||
|
@ -88,13 +90,7 @@ export default class CalendarFeedSummary extends React.Component<ICalendarFeedSu
|
|||
public render(): React.ReactElement<ICalendarFeedSummaryProps> {
|
||||
const {
|
||||
isConfigured,
|
||||
isNarrow,
|
||||
} = this.props;
|
||||
const {
|
||||
events,
|
||||
isLoading,
|
||||
error
|
||||
} = this.state;
|
||||
|
||||
// if we're not configured, show the placeholder
|
||||
if (!isConfigured) {
|
||||
|
@ -230,7 +226,6 @@ export default class CalendarFeedSummary extends React.Component<ICalendarFeedSu
|
|||
*/
|
||||
private _renderNarrowList(): JSX.Element {
|
||||
const {
|
||||
isLoading,
|
||||
events,
|
||||
currentPage
|
||||
} = this.state;
|
||||
|
@ -288,10 +283,10 @@ export default class CalendarFeedSummary extends React.Component<ICalendarFeedSu
|
|||
*/
|
||||
private _renderNormalList(): JSX.Element {
|
||||
const {
|
||||
events,
|
||||
isLoading } = this.state;
|
||||
events } = this.state;
|
||||
const isEditMode: boolean = this.props.displayMode === DisplayMode.Edit;
|
||||
|
||||
console.log("EVENTS", events);
|
||||
return (<div>
|
||||
<div>
|
||||
<div role="application">
|
||||
|
@ -364,30 +359,4 @@ export default class CalendarFeedSummary extends React.Component<ICalendarFeedSu
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves events in cache with an expiry date
|
||||
* @param events an array of events to save in cache
|
||||
*/
|
||||
private _setCache(events: ICalendarEvent[]): void {
|
||||
const { Name, FeedUrl, CacheDuration } = this.props.provider;
|
||||
|
||||
// don't cache if we haven't set a cache duration
|
||||
if (CacheDuration === undefined || CacheDuration === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const expiry: moment.Moment = moment().add(CacheDuration, "minutes");
|
||||
|
||||
// we use minutes instead of milliseconds, it doesn't make sense that
|
||||
// people want to cache a feed for milliseconds, or seconds
|
||||
// but feel free to change it to suit your needs
|
||||
const cache: IFeedCache = {
|
||||
feedType: Name,
|
||||
feedUrl: FeedUrl,
|
||||
events: events,
|
||||
expiry: expiry
|
||||
};
|
||||
localStorage.setItem(CacheKey, JSON.stringify(cache));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,10 +5,10 @@
|
|||
* file because that's what the Office UI Fabric team does and
|
||||
* I kinda liked it.
|
||||
*/
|
||||
import { DisplayMode } from '@microsoft/sp-core-library';
|
||||
import { IWebPartContext } from '@microsoft/sp-webpart-base';
|
||||
import { Moment } from 'moment';
|
||||
import { ICalendarEvent, ICalendarService } from '../../../shared/services/CalendarService';
|
||||
import { DisplayMode } from "@microsoft/sp-core-library";
|
||||
import { IWebPartContext } from "@microsoft/sp-webpart-base";
|
||||
import { Moment } from "moment";
|
||||
import { ICalendarEvent, ICalendarService } from "../../../shared/services/CalendarService";
|
||||
|
||||
/**
|
||||
* The props for the calendar feed summary component
|
||||
|
@ -42,4 +42,4 @@ export interface IFeedCache {
|
|||
expiry: Moment;
|
||||
feedType: string;
|
||||
feedUrl: string;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,8 @@ define([], function() {
|
|||
"ErrorInvalidiCalFeed": "The URL you provided does not appear to be an iCal feed. Are you sure you selected the right feed type?",
|
||||
"ErrorInvalidWordPressFeed": "The URL you provided does not appear to be a WordPress feed. Are you sure you selected the right feed type?",
|
||||
"AddToCalendarAriaLabel": "Press enter to download the calendar file to your device.",
|
||||
"AddToCalendarButtonLabel": "Add to my calendar"
|
||||
"AddToCalendarButtonLabel": "Add to my calendar",
|
||||
"AllDayDateFormat": "dddd, MMMM Do YYYY",
|
||||
"LocalizedTimeFormat": "llll"
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -50,6 +50,8 @@ declare interface ICalendarFeedSummaryWebPartStrings {
|
|||
ErrorInvalidWordPressFeed: string;
|
||||
AddToCalendarAriaLabel: string;
|
||||
AddToCalendarButtonLabel: string;
|
||||
AllDayDateFormat: string;
|
||||
LocalizedTimeFormat: string;
|
||||
}
|
||||
|
||||
declare module 'CalendarFeedSummaryWebPartStrings' {
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/en-us/json-schemas/teams/v1.2/MicrosoftTeams.schema.json",
|
||||
"manifestVersion": "1.2",
|
||||
"packageName": "CalendarFeedSummary",
|
||||
"id": "0459b501-da31-43c7-9a9a-d5c59cc2d667",
|
||||
"version": "0.1",
|
||||
"developer": {
|
||||
"name": "SPFx + Teams Dev",
|
||||
"websiteUrl": "https://products.office.com/en-us/sharepoint/collaboration",
|
||||
"privacyUrl": "https://privacy.microsoft.com/en-us/privacystatement",
|
||||
"termsOfUseUrl": "https://www.microsoft.com/en-us/servicesagreement"
|
||||
},
|
||||
"name": {
|
||||
"short": "CalendarFeedSummary"
|
||||
},
|
||||
"description": {
|
||||
"short": "Shows a summary view of a list of calendar events retrieved from an external feed.",
|
||||
"full": "Shows a summary view of a list of calendar events retrieved from an external feed."
|
||||
},
|
||||
"icons": {
|
||||
"outline": "tab20x20.png",
|
||||
"color": "tab96x96.png"
|
||||
},
|
||||
"accentColor": "#004578",
|
||||
"configurableTabs": [
|
||||
{
|
||||
"configurationUrl": "https://{teamSiteDomain}{teamSitePath}/_layouts/15/TeamsLogon.aspx?SPFX=true&dest={teamSitePath}/_layouts/15/teamshostedapp.aspx%3FopenPropertyPane=true%26teams%26componentId=0459b501-da31-43c7-9a9a-d5c59cc2d667",
|
||||
"canUpdateConfiguration": false,
|
||||
"scopes": [
|
||||
"team"
|
||||
]
|
||||
}
|
||||
],
|
||||
"validDomains": [
|
||||
"*.login.microsoftonline.com",
|
||||
"*.sharepoint.com",
|
||||
"*.sharepoint-df.com",
|
||||
"spoppe-a.akamaihd.net",
|
||||
"spoprod-a.akamaihd.net",
|
||||
"resourceseng.blob.core.windows.net",
|
||||
"msft.spoppe.com"
|
||||
],
|
||||
"webApplicationInfo": {
|
||||
"resource": "https://{teamSiteDomain}",
|
||||
"id": "00000003-0000-0ff1-ce00-000000000000"
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 933 B |
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
|
@ -1,14 +1,15 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "node",
|
||||
"target": "es5",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"jsx": "react",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"experimentalDecorators": true,
|
||||
"skipLibCheck": true,
|
||||
"outDir": "lib",
|
||||
"typeRoots": [
|
||||
"./node_modules/@types",
|
||||
"./node_modules/@microsoft"
|
||||
|
@ -22,5 +23,12 @@
|
|||
"dom",
|
||||
"es2015.collection"
|
||||
]
|
||||
}
|
||||
},
|
||||
"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