Merge branch 'master' into UpdateBigCalendar
|
@ -0,0 +1,25 @@
|
|||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
|
||||
[*]
|
||||
|
||||
# change these settings to your own preference
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# we recommend you to keep these unchanged
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[{package,bower}.json]
|
||||
indent_style = space
|
||||
indent_size = 2
|
|
@ -0,0 +1,32 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
|
||||
# Build generated files
|
||||
dist
|
||||
lib
|
||||
solution
|
||||
temp
|
||||
*.sppkg
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# OSX
|
||||
.DS_Store
|
||||
|
||||
# Visual Studio files
|
||||
.ntvs_analysis.dat
|
||||
.vs
|
||||
bin
|
||||
obj
|
||||
|
||||
# Resx Generated Code
|
||||
*.resx.ts
|
||||
|
||||
# Styles Generated Code
|
||||
*.scss.ts
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"isCreatingSolution": true,
|
||||
"environment": "spo",
|
||||
"version": "1.11.0",
|
||||
"libraryName": "react-avatar",
|
||||
"libraryId": "b96dfed7-ec48-4082-ba50-f6c7b09143c7",
|
||||
"packageManager": "npm",
|
||||
"isDomainIsolated": false,
|
||||
"componentType": "webpart"
|
||||
}
|
||||
}
|
|
@ -2,8 +2,7 @@
|
|||
|
||||
## Summary
|
||||
|
||||
This is a sample web part that helps user create their avatar and save as profile picture. User can even download their avatar as PNG file. This webpart can be useful in Intranet to help user create their avatar and save it as profile picture.
|
||||
|
||||
This is a sample web part that helps user create their avatar and save as profile picture. User can even download their avatar as PNG file. This web part can be useful in Intranet to help user create their avatar and save it as profile picture.
|
||||
|
||||
##
|
||||
![directory](/samples/react-avatar/assets/reactAvatarOutcome.gif)
|
||||
|
@ -16,7 +15,8 @@ This is a sample web part that helps user create their avatar and save as profil
|
|||
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
![drop](https://img.shields.io/badge/version-1.10.0-green.svg)
|
||||
|
||||
![SPFx 1.11](https://img.shields.io/badge/version-1.11.0-green.svg)
|
||||
|
||||
## Applies to
|
||||
|
||||
|
@ -55,6 +55,7 @@ Web Part Title | Text| no|
|
|||
|
||||
|
||||
## Solution
|
||||
|
||||
The web part Use avataaars library for creating avatars and MS Graph with User.ReadWrite and User.ReadWriteAll for saving avatar as current users Profile Picture.FileSaver for downloading avatar image as png file.
|
||||
|
||||
Solution|Author(s)
|
||||
|
@ -66,9 +67,11 @@ react Avatar|Kunj Sangani
|
|||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0.0|August 1, 2020|Initial release
|
||||
1.0.1|October 20, 2020|Update to SPFx 1.11.0
|
||||
|
||||
|
||||
## 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.**
|
||||
|
||||
---
|
||||
|
@ -81,9 +84,6 @@ Version|Date|Comments
|
|||
- `gulp build`
|
||||
- `gulp bundle --ship`
|
||||
- `gulp package-solution --ship`
|
||||
- `Add to AppCatalog and deploy`
|
||||
- Add to AppCatalog and deploy
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-avatar" />
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"solution": {
|
||||
"name": "react-avatars-client-side-solution",
|
||||
"id": "b96dfed7-ec48-4082-ba50-f6c7b09143c7",
|
||||
"version": "1.0.0.0",
|
||||
"version": "1.0.1.0",
|
||||
"includeClientSideAssets": true,
|
||||
"isDomainIsolated": false,
|
||||
"webApiPermissionRequests": [
|
||||
|
@ -11,7 +11,14 @@
|
|||
"resource": "Microsoft Graph",
|
||||
"scope": "User.ReadWrite"
|
||||
}
|
||||
]
|
||||
],
|
||||
"developer": {
|
||||
"name": "Contoso",
|
||||
"privacyUrl": "https://contoso.com/privacy",
|
||||
"termsOfUseUrl": "https://contoso.com/terms-of-use",
|
||||
"websiteUrl": "https://contoso.com/my-app",
|
||||
"mpnId": "000000"
|
||||
}
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/react-avatars.sppkg"
|
||||
|
|
|
@ -13,18 +13,14 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@material-ui/core": "^4.11.0",
|
||||
"@microsoft/sp-core-library": "1.10.0",
|
||||
"@microsoft/sp-lodash-subset": "1.10.0",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.10.0",
|
||||
"@microsoft/sp-property-pane": "1.10.0",
|
||||
"@microsoft/sp-webpart-base": "1.10.0",
|
||||
"@types/es6-promise": "0.0.33",
|
||||
"@types/react": "16.8.8",
|
||||
"@types/react-dom": "16.8.3",
|
||||
"@types/webpack-env": "1.13.1",
|
||||
"@microsoft/sp-core-library": "1.11.0",
|
||||
"@microsoft/sp-lodash-subset": "1.11.0",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.11.0",
|
||||
"@microsoft/sp-property-pane": "1.11.0",
|
||||
"@microsoft/sp-webpart-base": "1.11.0",
|
||||
"avataaars": "^1.2.1",
|
||||
"file-saver": "^2.0.2",
|
||||
"office-ui-fabric-react": "6.189.2",
|
||||
"office-ui-fabric-react": "6.214.0",
|
||||
"react": "16.8.5",
|
||||
"react-dom": "16.8.5"
|
||||
},
|
||||
|
@ -32,14 +28,14 @@
|
|||
"@types/react": "16.8.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/sp-build-web": "1.10.0",
|
||||
"@microsoft/sp-tslint-rules": "1.10.0",
|
||||
"@microsoft/sp-module-interfaces": "1.10.0",
|
||||
"@microsoft/sp-webpart-workbench": "1.10.0",
|
||||
"@microsoft/rush-stack-compiler-3.3": "0.3.5",
|
||||
"gulp": "~3.9.1",
|
||||
"@microsoft/sp-build-web": "1.11.0",
|
||||
"@microsoft/sp-module-interfaces": "1.11.0",
|
||||
"@microsoft/sp-tslint-rules": "1.11.0",
|
||||
"@microsoft/sp-webpart-workbench": "1.11.0",
|
||||
"@types/chai": "3.4.34",
|
||||
"@types/mocha": "2.2.38",
|
||||
"ajv": "~5.2.2"
|
||||
"ajv": "~5.2.2",
|
||||
"gulp": "~3.9.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,8 @@
|
|||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
|
|
|
@ -104,13 +104,15 @@ Start Date | Date | yes | Event Date
|
|||
End Date| Date| yes | Event Date
|
||||
|
||||
## Solution
|
||||
The Web Part Use PnPjs library, Office-ui-fabric-react components. react Big-Calendar Compoment
|
||||
|
||||
The Web Part Use PnPjs library, Office-ui-fabric-react components. react Big-Calendar Component
|
||||
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
Calendar Web Part|João Mendes
|
||||
Calendar Web Part|Mohamed Derhalli
|
||||
Calendar Web Part (Upgrade)|Hugo Bernier ([@bernier](https://twitter.com/bernierh), [Tahoe Ninjas](https://tahoeninjas.blog/))
|
||||
Calendar Web Part|Nanddeep Nachan ([@NanddeepNachan](https://twitter.com/NanddeepNachan))
|
||||
|
||||
## Version history
|
||||
|
||||
|
@ -120,6 +122,7 @@ Version|Date|Comments
|
|||
1.0.1|June 10, 2019|update add recurrence events
|
||||
1.0.2|April 25, 2020|Update styles according to the applied theme
|
||||
1.0.3|June 06, 2020|Upgrade to SPFx 1.10.0
|
||||
1.0.4|October 18, 2020|Added support for all-day events
|
||||
|
||||
## Disclaimer
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"solution": {
|
||||
"name": "react-calendar-client-side-solution",
|
||||
"id": "3a13208b-3874-4036-9262-4edd22e88187",
|
||||
"version": "1.0.0.1",
|
||||
"version": "1.0.4.0",
|
||||
"includeClientSideAssets": true,
|
||||
"skipFeatureDeployment": true,
|
||||
"isDomainIsolated": false
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "react-calendar",
|
||||
"main": "lib/index.js",
|
||||
"version": "1.0.2",
|
||||
"version": "1.0.4",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
|
|
|
@ -1,33 +1,34 @@
|
|||
import { IEventData } from '../../services/IEventData';
|
||||
import { IUserPermissions } from '../../services/IUserPermissions';
|
||||
import { DayOfWeek} from 'office-ui-fabric-react/lib/DatePicker';
|
||||
import { IDropdownOption } from 'office-ui-fabric-react/';
|
||||
import { DayOfWeek } from 'office-ui-fabric-react/lib/DatePicker';
|
||||
import { IDropdownOption } from 'office-ui-fabric-react/';
|
||||
export interface IEventState {
|
||||
showPanel: boolean;
|
||||
eventData:IEventData;
|
||||
eventData: IEventData;
|
||||
firstDayOfWeek?: DayOfWeek;
|
||||
startSelectedHour: IDropdownOption ;
|
||||
startSelectedMin: IDropdownOption ;
|
||||
endSelectedHour: IDropdownOption ;
|
||||
endSelectedMin: IDropdownOption ;
|
||||
startSelectedHour: IDropdownOption;
|
||||
startSelectedMin: IDropdownOption;
|
||||
endSelectedHour: IDropdownOption;
|
||||
endSelectedMin: IDropdownOption;
|
||||
startDate?: Date;
|
||||
endDate?: Date;
|
||||
editorState?: any;
|
||||
selectedUsers: string[];
|
||||
locationLatitude: number;
|
||||
locationLongitude: number;
|
||||
errorMessage?:string;
|
||||
hasError?:boolean;
|
||||
errorMessage?: string;
|
||||
hasError?: boolean;
|
||||
disableButton?: boolean;
|
||||
isSaving?:boolean;
|
||||
isDeleting?:boolean;
|
||||
displayDialog:boolean;
|
||||
isSaving?: boolean;
|
||||
isDeleting?: boolean;
|
||||
displayDialog: boolean;
|
||||
userPermissions?: IUserPermissions;
|
||||
isloading:boolean;
|
||||
isloading: boolean;
|
||||
isAllDayEvent: boolean;
|
||||
siteRegionalSettings: any;
|
||||
recurrenceSeriesEdited?:boolean;
|
||||
showRecurrenceSeriesInfo:boolean;
|
||||
newRecurrenceEvent:boolean;
|
||||
recurrenceAction:string;
|
||||
recurrenceDescription?:string;
|
||||
recurrenceSeriesEdited?: boolean;
|
||||
showRecurrenceSeriesInfo: boolean;
|
||||
newRecurrenceEvent: boolean;
|
||||
recurrenceAction: string;
|
||||
recurrenceDescription?: string;
|
||||
}
|
||||
|
|
|
@ -79,7 +79,6 @@ export class Event extends React.Component<IEventProps, IEventState> {
|
|||
navigator.geolocation.getCurrentPosition((position) => {
|
||||
this.latitude = position.coords.latitude;
|
||||
this.longitude = position.coords.longitude;
|
||||
|
||||
});
|
||||
} else {
|
||||
/* geolocation IS NOT available */
|
||||
|
@ -104,10 +103,11 @@ export class Event extends React.Component<IEventProps, IEventState> {
|
|||
isSaving: false,
|
||||
displayDialog: false,
|
||||
isloading: false,
|
||||
isAllDayEvent: this.props.event && this.props.event.fAllDayEvent,
|
||||
siteRegionalSettings: undefined,
|
||||
recurrenceSeriesEdited: false,
|
||||
showRecurrenceSeriesInfo:false,
|
||||
newRecurrenceEvent:false,
|
||||
showRecurrenceSeriesInfo: false,
|
||||
newRecurrenceEvent: false,
|
||||
recurrenceAction: 'display',
|
||||
userPermissions: { hasPermissionAdd: false, hasPermissionDelete: false, hasPermissionEdit: false, hasPermissionView: false },
|
||||
};
|
||||
|
@ -148,13 +148,15 @@ export class Event extends React.Component<IEventProps, IEventState> {
|
|||
* @memberof Event
|
||||
*/
|
||||
private async onSave() {
|
||||
|
||||
let eventData: IEventData = this.state.eventData;
|
||||
let panelMode = this.props.panelMode;
|
||||
|
||||
let startDate: string = null;
|
||||
let endDate: string = null;
|
||||
eventData.fRecurrence = false;
|
||||
|
||||
// set All day event
|
||||
eventData.fAllDayEvent = this.state.isAllDayEvent;
|
||||
|
||||
// if there are new Event recurrence or Edited recurrence series
|
||||
if (this.state.recurrenceSeriesEdited || this.state.newRecurrenceEvent) {
|
||||
eventData.RecurrenceData = this.returnedRecurrenceInfo.recurrenceData;
|
||||
|
@ -163,16 +165,17 @@ export class Event extends React.Component<IEventProps, IEventState> {
|
|||
|
||||
if (eventData.EventType == "0" && this.state.newRecurrenceEvent) {
|
||||
eventData.EventType = "1";
|
||||
eventData.fRecurrence= true;
|
||||
eventData.UID = getGUID();
|
||||
}
|
||||
if (eventData.EventType == "1" && this.state.recurrenceSeriesEdited) {
|
||||
eventData.fRecurrence= true;
|
||||
eventData.fRecurrence = true;
|
||||
eventData.UID = getGUID();
|
||||
}
|
||||
|
||||
} else {
|
||||
if (this.state.eventData.EventType == '1'){ // recurrence exception
|
||||
if (eventData.EventType == "1" && this.state.recurrenceSeriesEdited) {
|
||||
eventData.fRecurrence = true;
|
||||
eventData.UID = getGUID();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this.state.eventData.EventType == '1') { // recurrence exception
|
||||
eventData.RecurrenceID = eventData.EventDate.toString();
|
||||
eventData.MasterSeriesItemID = eventData.ID.toString();
|
||||
eventData.EventType = "4";
|
||||
|
@ -185,20 +188,19 @@ export class Event extends React.Component<IEventProps, IEventState> {
|
|||
endDate = `${moment(this.state.endDate).format('YYYY/MM/DD')}`;
|
||||
}
|
||||
|
||||
|
||||
// Start Date
|
||||
const startTime = `${this.state.startSelectedHour.key}:${this.state.startSelectedMin.key}`;
|
||||
const startDateTime = `${startDate} ${startTime}`;
|
||||
const start = moment(startDateTime, 'YYYY/MM/DD HH:mm').toLocaleString();
|
||||
eventData.EventDate = new Date(start);
|
||||
|
||||
// End Date
|
||||
const endTime = `${this.state.endSelectedHour.key}:${this.state.endSelectedMin.key}`;
|
||||
const endDateTime = `${endDate} ${endTime}`;
|
||||
const end = moment(endDateTime, 'YYYY/MM/DD HH:mm').toLocaleString();
|
||||
eventData.EndDate = new Date(end);
|
||||
|
||||
|
||||
// get Geolocation
|
||||
|
||||
eventData.geolocation = { Latitude: this.latitude, Longitude: this.longitude };
|
||||
const locationInfo = await this.spService.getGeoLactionName(this.latitude, this.longitude);
|
||||
eventData.location = locationInfo ? locationInfo.display_name : 'N/A';
|
||||
|
@ -213,7 +215,6 @@ export class Event extends React.Component<IEventProps, IEventState> {
|
|||
|
||||
try {
|
||||
for (const user of this.attendees) {
|
||||
|
||||
const userInfo: any = await this.spService.getUserByLoginName(user.id, this.props.siteUrl);
|
||||
eventData.attendes.push(Number(userInfo.Id));
|
||||
}
|
||||
|
@ -255,7 +256,7 @@ export class Event extends React.Component<IEventProps, IEventState> {
|
|||
* @param {number} [eventId]
|
||||
* @memberof Event
|
||||
*/
|
||||
private async renderEventData(eventId?: number) {
|
||||
private async renderEventData(eventId?: number) {
|
||||
|
||||
this.setState({ isloading: true });
|
||||
const event: IEventData = !eventId ? this.props.event : await this.spService.getEvent(this.props.siteUrl, this.props.listId, eventId);
|
||||
|
@ -479,7 +480,7 @@ export class Event extends React.Component<IEventProps, IEventState> {
|
|||
this.setState({ isDeleting: false });
|
||||
this.props.onDissmissPanel(true);
|
||||
} catch (error) {
|
||||
this.setState({ hasError: true, errorMessage: error.message, isDeleting: false, displayDialog:false });
|
||||
this.setState({ hasError: true, errorMessage: error.message, isDeleting: false, displayDialog: false });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -616,7 +617,7 @@ export class Event extends React.Component<IEventProps, IEventState> {
|
|||
}
|
||||
|
||||
return format("{}{} {} {}",
|
||||
frequency === 1 ? format(strings.everyFormat, frequency) : frequency === 2 ? format(strings.everySecondFormat, frequency): format(strings.everyNthFormat, frequency),
|
||||
frequency === 1 ? format(strings.everyFormat, frequency) : frequency === 2 ? format(strings.everySecondFormat, frequency) : format(strings.everyNthFormat, frequency),
|
||||
strings.weekLabel,
|
||||
strings.onLabel,
|
||||
days.join(", "));
|
||||
|
@ -634,7 +635,7 @@ export class Event extends React.Component<IEventProps, IEventState> {
|
|||
const day: number = parseInt(rule["day"]);
|
||||
|
||||
return format("{}{} {}",
|
||||
frequency === 1 ? format(strings.everyFormat, frequency) : frequency === 2 ? format(strings.everySecondFormat, frequency): format(strings.everyNthFormat, frequency),
|
||||
frequency === 1 ? format(strings.everyFormat, frequency) : frequency === 2 ? format(strings.everySecondFormat, frequency) : format(strings.everyNthFormat, frequency),
|
||||
strings.monthLabel,
|
||||
format(strings.onTheDayFormat, day)
|
||||
);
|
||||
|
@ -676,7 +677,7 @@ export class Event extends React.Component<IEventProps, IEventState> {
|
|||
switch (key) {
|
||||
case "monthFrequency":
|
||||
const frequency = parseInt(rule[key]);
|
||||
switch(frequency) {
|
||||
switch (frequency) {
|
||||
case 1:
|
||||
frequencyFormat = format(strings.everyFormat, frequency);
|
||||
break;
|
||||
|
@ -719,7 +720,7 @@ export class Event extends React.Component<IEventProps, IEventState> {
|
|||
let month: string;
|
||||
let day: string;
|
||||
for (let key of keys) {
|
||||
switch(key) {
|
||||
switch (key) {
|
||||
case "yearFrequency":
|
||||
const frequency = parseInt(rule[key]);
|
||||
const frequencyFormat = frequency == 1 ? strings.everyFormat : frequency == 2 ? strings.everySecondFormat : strings.everyNthFormat;
|
||||
|
@ -770,7 +771,7 @@ export class Event extends React.Component<IEventProps, IEventState> {
|
|||
let order: string;
|
||||
let dayTypeString: string;
|
||||
for (let key of keys) {
|
||||
switch(key) {
|
||||
switch (key) {
|
||||
case "yearFrequency":
|
||||
const frequency = parseInt(rule[key]);
|
||||
const frequencyFormat = frequency === 1 ? strings.everyFormat : frequency === 2 ? strings.everySecondFormat : strings.everyNthFormat;
|
||||
|
@ -814,37 +815,36 @@ export class Event extends React.Component<IEventProps, IEventState> {
|
|||
});
|
||||
|
||||
const recurrenceInfo: any = await promise;
|
||||
if(recurrenceInfo != null)
|
||||
{
|
||||
let keys = Object.keys(recurrenceInfo.recurrence.rule[0].repeat[0]);
|
||||
const recurrenceTypes = ["daily", "weekly", "monthly", "monthlyByDay", "yearly", "yearlyByDay"];
|
||||
for (var key of keys) {
|
||||
const rule = recurrenceInfo.recurrence.rule[0].repeat[0][key][0]['$'];
|
||||
switch(recurrenceTypes.indexOf(key)) {
|
||||
case 0:
|
||||
return this.parseDailyRule(rule);
|
||||
break;
|
||||
case 1:
|
||||
return this.parseWeeklyRule(rule);
|
||||
break;
|
||||
case 2:
|
||||
return this.parseMonthlyRule(rule);
|
||||
break;
|
||||
case 3:
|
||||
return this.parseMonthlyByDayRule(rule);
|
||||
break;
|
||||
case 4:
|
||||
return this.parseYearlyRule(rule);
|
||||
break;
|
||||
case 5:
|
||||
return this.parseYearlyByDayRule(rule);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
if (recurrenceInfo != null) {
|
||||
let keys = Object.keys(recurrenceInfo.recurrence.rule[0].repeat[0]);
|
||||
const recurrenceTypes = ["daily", "weekly", "monthly", "monthlyByDay", "yearly", "yearlyByDay"];
|
||||
for (var key of keys) {
|
||||
const rule = recurrenceInfo.recurrence.rule[0].repeat[0][key][0]['$'];
|
||||
switch (recurrenceTypes.indexOf(key)) {
|
||||
case 0:
|
||||
return this.parseDailyRule(rule);
|
||||
break;
|
||||
case 1:
|
||||
return this.parseWeeklyRule(rule);
|
||||
break;
|
||||
case 2:
|
||||
return this.parseMonthlyRule(rule);
|
||||
break;
|
||||
case 3:
|
||||
return this.parseMonthlyByDayRule(rule);
|
||||
break;
|
||||
case 4:
|
||||
return this.parseYearlyRule(rule);
|
||||
break;
|
||||
case 5:
|
||||
return this.parseYearlyByDayRule(rule);
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
|
@ -898,17 +898,17 @@ export class Event extends React.Component<IEventProps, IEventState> {
|
|||
<div>
|
||||
{
|
||||
(this.state.eventData && (this.state.eventData.EventType !== "0" && this.state.showRecurrenceSeriesInfo !== true)) ?
|
||||
<div>
|
||||
<h2 style={{ display: 'inline-block', verticalAlign: 'top' }}>{ strings.recurrenceEventLabel }</h2>
|
||||
{ this.state.recurrenceDescription ? <span style={{ display: 'block' }} >{ this.state.recurrenceDescription }</span> : null }
|
||||
<div>
|
||||
<h2 style={{ display: 'inline-block', verticalAlign: 'top' }}>{strings.recurrenceEventLabel}</h2>
|
||||
{this.state.recurrenceDescription ? <span style={{ display: 'block' }} >{this.state.recurrenceDescription}</span> : null}
|
||||
<DefaultButton
|
||||
style={{ display: 'inline-block', marginLeft: '330px', verticalAlign: 'top', width: 'auto' }}
|
||||
iconProps={{ iconName: 'RecurringEvent' }}
|
||||
allowDisabledFocus={true}
|
||||
onClick={this.onEditRecurrence}
|
||||
>
|
||||
{ strings.editRecurrenceSeries }
|
||||
</DefaultButton>
|
||||
{strings.editRecurrenceSeries}
|
||||
</DefaultButton>
|
||||
|
||||
</div>
|
||||
: ''
|
||||
|
@ -948,62 +948,66 @@ export class Event extends React.Component<IEventProps, IEventState> {
|
|||
hidden={this.state.showRecurrenceSeriesInfo}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: 'inline-block', verticalAlign: 'top', paddingRight: 10 }}>
|
||||
<Dropdown
|
||||
selectedKey={this.state.startSelectedHour.key}
|
||||
onChange={this.onStartChangeHour}
|
||||
label={strings.StartHourLabel}
|
||||
disabled={this.state.userPermissions.hasPermissionAdd || this.state.userPermissions.hasPermissionEdit ? false : true}
|
||||
options={[
|
||||
{ key: '00', text: '00' },
|
||||
{ key: '01', text: '01' },
|
||||
{ key: '02', text: '02' },
|
||||
{ key: '03', text: '03' },
|
||||
{ key: '04', text: '04' },
|
||||
{ key: '05', text: '05' },
|
||||
{ key: '06', text: '06' },
|
||||
{ key: '07', text: '07' },
|
||||
{ key: '08', text: '08' },
|
||||
{ key: '09', text: '09' },
|
||||
{ key: '10', text: '10' },
|
||||
{ key: '11', text: '11' },
|
||||
{ key: '12', text: '12' },
|
||||
{ key: '13', text: '13' },
|
||||
{ key: '14', text: '14' },
|
||||
{ key: '15', text: '15' },
|
||||
{ key: '16', text: '16' },
|
||||
{ key: '17', text: '17' },
|
||||
{ key: '18', text: '18' },
|
||||
{ key: '19', text: '19' },
|
||||
{ key: '20', text: '20' },
|
||||
{ key: '21', text: '21' },
|
||||
{ key: '22', text: '22' },
|
||||
{ key: '23', text: '23' }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: 'inline-block', verticalAlign: 'top', }}>
|
||||
<Dropdown
|
||||
label={strings.StartMinLabel}
|
||||
selectedKey={this.state.startSelectedMin.key}
|
||||
onChange={this.onStartChangeMin}
|
||||
disabled={this.state.userPermissions.hasPermissionAdd || this.state.userPermissions.hasPermissionEdit ? false : true}
|
||||
options={[
|
||||
{ key: '00', text: '00' },
|
||||
{ key: '05', text: '05' },
|
||||
{ key: '10', text: '10' },
|
||||
{ key: '15', text: '15' },
|
||||
{ key: '20', text: '20' },
|
||||
{ key: '25', text: '25' },
|
||||
{ key: '30', text: '30' },
|
||||
{ key: '35', text: '35' },
|
||||
{ key: '40', text: '40' },
|
||||
{ key: '45', text: '45' },
|
||||
{ key: '50', text: '50' },
|
||||
{ key: '55', text: '55' }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
{!this.state.isAllDayEvent &&
|
||||
<div style={{ display: 'inline-block', verticalAlign: 'top', paddingRight: 10 }}>
|
||||
<Dropdown
|
||||
selectedKey={this.state.startSelectedHour.key}
|
||||
onChange={this.onStartChangeHour}
|
||||
label={strings.StartHourLabel}
|
||||
disabled={this.state.userPermissions.hasPermissionAdd || this.state.userPermissions.hasPermissionEdit ? false : true}
|
||||
options={[
|
||||
{ key: '00', text: '00' },
|
||||
{ key: '01', text: '01' },
|
||||
{ key: '02', text: '02' },
|
||||
{ key: '03', text: '03' },
|
||||
{ key: '04', text: '04' },
|
||||
{ key: '05', text: '05' },
|
||||
{ key: '06', text: '06' },
|
||||
{ key: '07', text: '07' },
|
||||
{ key: '08', text: '08' },
|
||||
{ key: '09', text: '09' },
|
||||
{ key: '10', text: '10' },
|
||||
{ key: '11', text: '11' },
|
||||
{ key: '12', text: '12' },
|
||||
{ key: '13', text: '13' },
|
||||
{ key: '14', text: '14' },
|
||||
{ key: '15', text: '15' },
|
||||
{ key: '16', text: '16' },
|
||||
{ key: '17', text: '17' },
|
||||
{ key: '18', text: '18' },
|
||||
{ key: '19', text: '19' },
|
||||
{ key: '20', text: '20' },
|
||||
{ key: '21', text: '21' },
|
||||
{ key: '22', text: '22' },
|
||||
{ key: '23', text: '23' }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
{!this.state.isAllDayEvent &&
|
||||
<div style={{ display: 'inline-block', verticalAlign: 'top', }}>
|
||||
<Dropdown
|
||||
label={strings.StartMinLabel}
|
||||
selectedKey={this.state.startSelectedMin.key}
|
||||
onChange={this.onStartChangeMin}
|
||||
disabled={this.state.userPermissions.hasPermissionAdd || this.state.userPermissions.hasPermissionEdit ? false : true}
|
||||
options={[
|
||||
{ key: '00', text: '00' },
|
||||
{ key: '05', text: '05' },
|
||||
{ key: '10', text: '10' },
|
||||
{ key: '15', text: '15' },
|
||||
{ key: '20', text: '20' },
|
||||
{ key: '25', text: '25' },
|
||||
{ key: '30', text: '30' },
|
||||
{ key: '35', text: '35' },
|
||||
{ key: '40', text: '40' },
|
||||
{ key: '45', text: '45' },
|
||||
{ key: '50', text: '50' },
|
||||
{ key: '55', text: '55' }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
<br />
|
||||
<div style={{ display: 'inline-block', verticalAlign: 'top', paddingRight: 10 }}>
|
||||
<DatePicker
|
||||
|
@ -1020,75 +1024,94 @@ export class Event extends React.Component<IEventProps, IEventState> {
|
|||
hidden={this.state.showRecurrenceSeriesInfo}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: 'inline-block', verticalAlign: 'top', paddingRight: 10 }}>
|
||||
<Dropdown
|
||||
selectedKey={this.state.endSelectedHour.key}
|
||||
onChange={this.onEndChangeHour}
|
||||
label={strings.EndHourLabel}
|
||||
disabled={this.state.userPermissions.hasPermissionAdd || this.state.userPermissions.hasPermissionEdit ? false : true}
|
||||
options={[
|
||||
{ key: '00', text: '00' },
|
||||
{ key: '01', text: '01' },
|
||||
{ key: '02', text: '02' },
|
||||
{ key: '03', text: '03' },
|
||||
{ key: '04', text: '04' },
|
||||
{ key: '05', text: '05' },
|
||||
{ key: '06', text: '06' },
|
||||
{ key: '07', text: '07' },
|
||||
{ key: '08', text: '08' },
|
||||
{ key: '09', text: '09' },
|
||||
{ key: '10', text: '10' },
|
||||
{ key: '11', text: '11' },
|
||||
{ key: '12', text: '12' },
|
||||
{ key: '13', text: '13' },
|
||||
{ key: '14', text: '14' },
|
||||
{ key: '15', text: '15' },
|
||||
{ key: '16', text: '16' },
|
||||
{ key: '17', text: '17' },
|
||||
{ key: '18', text: '18' },
|
||||
{ key: '19', text: '19' },
|
||||
{ key: '20', text: '20' },
|
||||
{ key: '21', text: '21' },
|
||||
{ key: '22', text: '22' },
|
||||
{ key: '23', text: '23' }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
<div style={{ display: 'inline-block', verticalAlign: 'top', }}>
|
||||
<Dropdown
|
||||
label={strings.EndMinLabel}
|
||||
selectedKey={this.state.endSelectedMin.key}
|
||||
onChange={this.onEndChangeMin}
|
||||
disabled={this.state.userPermissions.hasPermissionAdd || this.state.userPermissions.hasPermissionEdit ? false : true}
|
||||
options={[
|
||||
{ key: '00', text: '00' },
|
||||
{ key: '05', text: '05' },
|
||||
{ key: '10', text: '10' },
|
||||
{ key: '15', text: '15' },
|
||||
{ key: '20', text: '20' },
|
||||
{ key: '25', text: '25' },
|
||||
{ key: '30', text: '30' },
|
||||
{ key: '35', text: '35' },
|
||||
{ key: '40', text: '40' },
|
||||
{ key: '45', text: '45' },
|
||||
{ key: '50', text: '50' },
|
||||
{ key: '55', text: '55' },
|
||||
{ key: '59', text: '59' }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
{!this.state.isAllDayEvent &&
|
||||
<div style={{ display: 'inline-block', verticalAlign: 'top', paddingRight: 10 }}>
|
||||
<Dropdown
|
||||
selectedKey={this.state.endSelectedHour.key}
|
||||
onChange={this.onEndChangeHour}
|
||||
label={strings.EndHourLabel}
|
||||
disabled={this.state.userPermissions.hasPermissionAdd || this.state.userPermissions.hasPermissionEdit ? false : true}
|
||||
options={[
|
||||
{ key: '00', text: '00' },
|
||||
{ key: '01', text: '01' },
|
||||
{ key: '02', text: '02' },
|
||||
{ key: '03', text: '03' },
|
||||
{ key: '04', text: '04' },
|
||||
{ key: '05', text: '05' },
|
||||
{ key: '06', text: '06' },
|
||||
{ key: '07', text: '07' },
|
||||
{ key: '08', text: '08' },
|
||||
{ key: '09', text: '09' },
|
||||
{ key: '10', text: '10' },
|
||||
{ key: '11', text: '11' },
|
||||
{ key: '12', text: '12' },
|
||||
{ key: '13', text: '13' },
|
||||
{ key: '14', text: '14' },
|
||||
{ key: '15', text: '15' },
|
||||
{ key: '16', text: '16' },
|
||||
{ key: '17', text: '17' },
|
||||
{ key: '18', text: '18' },
|
||||
{ key: '19', text: '19' },
|
||||
{ key: '20', text: '20' },
|
||||
{ key: '21', text: '21' },
|
||||
{ key: '22', text: '22' },
|
||||
{ key: '23', text: '23' }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
{!this.state.isAllDayEvent &&
|
||||
<div style={{ display: 'inline-block', verticalAlign: 'top', }}>
|
||||
<Dropdown
|
||||
label={strings.EndMinLabel}
|
||||
selectedKey={this.state.endSelectedMin.key}
|
||||
onChange={this.onEndChangeMin}
|
||||
disabled={this.state.userPermissions.hasPermissionAdd || this.state.userPermissions.hasPermissionEdit ? false : true}
|
||||
options={[
|
||||
{ key: '00', text: '00' },
|
||||
{ key: '05', text: '05' },
|
||||
{ key: '10', text: '10' },
|
||||
{ key: '15', text: '15' },
|
||||
{ key: '20', text: '20' },
|
||||
{ key: '25', text: '25' },
|
||||
{ key: '30', text: '30' },
|
||||
{ key: '35', text: '35' },
|
||||
{ key: '40', text: '40' },
|
||||
{ key: '45', text: '45' },
|
||||
{ key: '50', text: '50' },
|
||||
{ key: '55', text: '55' },
|
||||
{ key: '59', text: '59' }
|
||||
]}
|
||||
/>
|
||||
</div>
|
||||
}
|
||||
<Label>{this.state.siteRegionalSettings ? this.state.siteRegionalSettings.Description : ''}</Label>
|
||||
<br />
|
||||
{
|
||||
|
||||
<div style={{ display: 'inline-block', verticalAlign: 'top', width: '200px' }}>
|
||||
<Toggle
|
||||
defaultChecked={this.state.eventData && this.state.eventData.fAllDayEvent}
|
||||
inlineLabel={true}
|
||||
label={strings.allDayEventLabel}
|
||||
onText={strings.onLabel}
|
||||
offText={strings.offLabel}
|
||||
onChange={(ev, checked: boolean) => {
|
||||
ev.preventDefault();
|
||||
this.setState({ isAllDayEvent: checked });
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<br />
|
||||
|
||||
{
|
||||
this.state.eventData && (this.state.eventData.EventType == "0") ?
|
||||
<div style={{ display: 'inline-block', verticalAlign: 'top', width: '200px' }}>
|
||||
<Toggle
|
||||
defaultChecked={false}
|
||||
inlineLabel={true}
|
||||
label={ strings.ifRecurrenceLabel }
|
||||
onText={ strings.onLabel }
|
||||
offText={ strings.offLabel }
|
||||
label={strings.ifRecurrenceLabel}
|
||||
onText={strings.onLabel}
|
||||
offText={strings.offLabel}
|
||||
onChange={(ev, checked: boolean) => {
|
||||
ev.preventDefault();
|
||||
this.setState({ showRecurrenceSeriesInfo: checked, newRecurrenceEvent: checked });
|
||||
|
@ -1109,12 +1132,11 @@ export class Event extends React.Component<IEventProps, IEventState> {
|
|||
siteUrl={this.props.siteUrl}
|
||||
returnRecurrenceData={this.returnRecurrenceInfo}
|
||||
>
|
||||
|
||||
</EventRecurrenceInfo>
|
||||
)
|
||||
}
|
||||
|
||||
< Label > {strings.eventDescriptionLabel }</Label>
|
||||
<Label>{strings.eventDescriptionLabel}</Label>
|
||||
|
||||
<div className={styles.description}>
|
||||
<Editor
|
||||
|
@ -1125,7 +1147,6 @@ export class Event extends React.Component<IEventProps, IEventState> {
|
|||
</div>
|
||||
<div>
|
||||
<PeoplePicker
|
||||
|
||||
webAbsoluteUrl={this.props.siteUrl}
|
||||
context={this.props.context}
|
||||
titleText={strings.AttendeesLabel}
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
export interface IEventData {
|
||||
Id?:number;
|
||||
ID?:number;
|
||||
Id?: number;
|
||||
ID?: number;
|
||||
title: string;
|
||||
Description?: any;
|
||||
location?:string;
|
||||
location?: string;
|
||||
EventDate: Date;
|
||||
EndDate: Date;
|
||||
color?:string;
|
||||
color?: string;
|
||||
ownerInitial?: string;
|
||||
ownerPhoto?:string;
|
||||
ownerEmail?:string;
|
||||
ownerName?:string;
|
||||
ownerPhoto?: string;
|
||||
ownerEmail?: string;
|
||||
ownerName?: string;
|
||||
fAllDayEvent?: boolean;
|
||||
attendes?: number[];
|
||||
geolocation?: {Longitude:number, Latitude: number};
|
||||
geolocation?: { Longitude: number, Latitude: number };
|
||||
Category?: string;
|
||||
Duration?: number;
|
||||
RecurrenceData?:string;
|
||||
fRecurrence?:string | boolean;
|
||||
EventType?:string;
|
||||
UID?:string;
|
||||
RecurrenceData?: string;
|
||||
fRecurrence?: string | boolean;
|
||||
EventType?: string;
|
||||
UID?: string;
|
||||
RecurrenceID?: string;
|
||||
MasterSeriesItemID?: string;
|
||||
}
|
||||
|
|
|
@ -76,7 +76,6 @@ export default class spservices {
|
|||
let results = null;
|
||||
try {
|
||||
const web = new Web(siteUrl);
|
||||
|
||||
const siteTimeZoneHours: number = await this.getSiteTimeZoneHours(siteUrl);
|
||||
|
||||
results = await web.lists.getById(listId).items.add({
|
||||
|
@ -87,7 +86,7 @@ export default class spservices {
|
|||
EventDate: new Date(moment(newEvent.EventDate).add(siteTimeZoneHours, 'hours').toISOString()),
|
||||
EndDate: new Date(moment(newEvent.EndDate).add(siteTimeZoneHours, 'hours').toISOString()),
|
||||
Location: newEvent.location,
|
||||
fAllDayEvent: false,
|
||||
fAllDayEvent: newEvent.fAllDayEvent,
|
||||
fRecurrence: newEvent.fRecurrence,
|
||||
Category: newEvent.Category,
|
||||
EventType: newEvent.EventType,
|
||||
|
@ -96,7 +95,8 @@ export default class spservices {
|
|||
MasterSeriesItemID: newEvent.MasterSeriesItemID,
|
||||
RecurrenceID: newEvent.RecurrenceID ? moment(newEvent.RecurrenceID).add(siteTimeZoneHours, 'hours').toISOString() : undefined,
|
||||
});
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
return results;
|
||||
|
@ -117,13 +117,13 @@ export default class spservices {
|
|||
try {
|
||||
const siteTimeZoneHours: number = await this.getSiteTimeZoneHours(siteUrl);
|
||||
const web = new Web(siteUrl);
|
||||
|
||||
//"Title","fRecurrence", "fAllDayEvent","EventDate", "EndDate", "Description","ID", "Location","Geolocation","ParticipantsPickerId"
|
||||
const event = await web.lists.getById(listId).items.usingCaching().getById(eventId)
|
||||
.select("RecurrenceID", "MasterSeriesItemID", "Id", "ID", "ParticipantsPickerId", "EventType", "Title", "Description", "EventDate", "EndDate", "Location", "Author/SipAddress", "Author/Title", "Geolocation", "fAllDayEvent", "fRecurrence", "RecurrenceData", "RecurrenceData", "Duration", "Category", "UID")
|
||||
.expand("Author")
|
||||
.get();
|
||||
|
||||
|
||||
returnEvent = {
|
||||
Id: event.ID,
|
||||
ID: event.ID,
|
||||
|
@ -139,7 +139,7 @@ export default class spservices {
|
|||
color: '',
|
||||
ownerName: event.Author.Title,
|
||||
attendes: event.ParticipantsPickerId,
|
||||
fAllDayEvent: false,
|
||||
fAllDayEvent: event.fAllDayEvent,
|
||||
geolocation: { Longitude: event.Geolocation ? event.Geolocation.Longitude : 0, Latitude: event.Geolocation ? event.Geolocation.Latitude : 0 },
|
||||
Category: event.Category,
|
||||
Duration: event.Duration,
|
||||
|
@ -149,13 +149,13 @@ export default class spservices {
|
|||
RecurrenceID: event.RecurrenceID,
|
||||
MasterSeriesItemID: event.MasterSeriesItemID,
|
||||
};
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
return returnEvent;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {IEventData} newEvent
|
||||
|
@ -167,13 +167,12 @@ export default class spservices {
|
|||
public async updateEvent(updateEvent: IEventData, siteUrl: string, listId: string) {
|
||||
let results = null;
|
||||
try {
|
||||
|
||||
// delete all recursive extentions before update recurrence event
|
||||
// delete all recursive extentions before update recurrence event
|
||||
if (updateEvent.EventType.toString() == "1") await this.deleteRecurrenceExceptions(updateEvent, siteUrl, listId);
|
||||
|
||||
const siteTimeZoneHours: number = await this.getSiteTimeZoneHours(siteUrl);
|
||||
|
||||
const web = new Web(siteUrl);
|
||||
|
||||
//"Title","fRecurrence", "fAllDayEvent","EventDate", "EndDate", "Description","ID", "Location","Geolocation","ParticipantsPickerId"
|
||||
let newItem: any = {
|
||||
Title: updateEvent.title,
|
||||
|
@ -183,12 +182,13 @@ export default class spservices {
|
|||
EventDate: new Date(moment(updateEvent.EventDate).add(siteTimeZoneHours, 'hours').toISOString()),
|
||||
EndDate: new Date(moment(updateEvent.EndDate).add(siteTimeZoneHours, 'hours').toISOString()),
|
||||
Location: updateEvent.location,
|
||||
fAllDayEvent: false,
|
||||
fAllDayEvent: updateEvent.fAllDayEvent,
|
||||
fRecurrence: updateEvent.fRecurrence,
|
||||
Category: updateEvent.Category,
|
||||
RecurrenceData: updateEvent.RecurrenceData ? await this.deCodeHtmlEntities(updateEvent.RecurrenceData) : "",
|
||||
EventType: updateEvent.EventType,
|
||||
};
|
||||
|
||||
if (updateEvent.UID) {
|
||||
newItem.UID = updateEvent.UID;
|
||||
}
|
||||
|
@ -197,7 +197,8 @@ export default class spservices {
|
|||
}
|
||||
|
||||
results = await web.lists.getById(listId).items.getById(updateEvent.Id).update(newItem);
|
||||
} catch (error) {
|
||||
}
|
||||
catch (error) {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
return results;
|
||||
|
@ -489,6 +490,7 @@ export default class spservices {
|
|||
|
||||
if (results && results.Row.length > 0) {
|
||||
let event: any = '';
|
||||
|
||||
for (event of results.Row) {
|
||||
const initialsArray: string[] = event.Author[0].title.split(' ');
|
||||
const initials: string = initialsArray[0].charAt(0) + initialsArray[initialsArray.length - 1].charAt(0);
|
||||
|
@ -501,22 +503,20 @@ export default class spservices {
|
|||
const CategoryColorValue: any[] = categoryColor.filter((value) => {
|
||||
return value.category == event.Category;
|
||||
});
|
||||
const isAllDayEvent: boolean = event.fAllDayEvent === "Yes";
|
||||
|
||||
for (const attendee of event.ParticipantsPicker) {
|
||||
attendees.push(parseInt(attendee.id));
|
||||
}
|
||||
|
||||
|
||||
|
||||
events.push({
|
||||
Id: event.ID,
|
||||
ID: event.ID,
|
||||
EventType: event.EventType,
|
||||
title: await this.deCodeHtmlEntities(event.Title),
|
||||
Description: event.Description,
|
||||
|
||||
EventDate: new Date(moment(event.EventDate).subtract((siteTimeZoneHours), 'hour').toISOString()),
|
||||
|
||||
EndDate: new Date(moment(event.EndDate).subtract(siteTimeZoneHours, 'hour').toISOString()),
|
||||
EventDate: isAllDayEvent ? new Date(moment(event.EventDate).toISOString()) : new Date(moment(event.EventDate).subtract((siteTimeZoneHours), 'hour').toISOString()),
|
||||
EndDate: isAllDayEvent ? new Date(moment(event.EndDate).toISOString()) : new Date(moment(event.EndDate).subtract(siteTimeZoneHours, 'hour').toISOString()),
|
||||
location: event.Location,
|
||||
ownerEmail: event.Author[0].email,
|
||||
ownerPhoto: userPictureUrl ?
|
||||
|
@ -525,7 +525,7 @@ export default class spservices {
|
|||
color: CategoryColorValue.length > 0 ? CategoryColorValue[0].color : '#1a75ff', // blue default
|
||||
ownerName: event.Author[0].title,
|
||||
attendes: attendees,
|
||||
fAllDayEvent: false,
|
||||
fAllDayEvent: isAllDayEvent,
|
||||
geolocation: { Longitude: parseFloat(geolocation[0]), Latitude: parseFloat(geolocation[1]) },
|
||||
Category: event.Category,
|
||||
Duration: event.Duration,
|
||||
|
@ -540,6 +540,7 @@ export default class spservices {
|
|||
let parseEvt: parseRecurrentEvent = new parseRecurrentEvent();
|
||||
events = parseEvt.parseEvents(events, null, null);
|
||||
}
|
||||
|
||||
// Return Data
|
||||
return events;
|
||||
} catch (error) {
|
||||
|
|
|
@ -115,6 +115,7 @@ define([], function () {
|
|||
showMore: "more",
|
||||
recurrenceEventLabel: "Recurrence Event",
|
||||
editRecurrenceSeries: "Edit Recurrence Series",
|
||||
allDayEventLabel: "All Day Event ?",
|
||||
ifRecurrenceLabel: "Recurrence ?",
|
||||
onLabel: "On",
|
||||
offLabel: "Off",
|
||||
|
|
|
@ -115,6 +115,7 @@ declare interface ICalendarWebPartStrings {
|
|||
showMore: string;
|
||||
recurrenceEventLabel: string;
|
||||
editRecurrenceSeries: string;
|
||||
allDayEventLabel: string;
|
||||
ifRecurrenceLabel: string;
|
||||
onLabel: string;
|
||||
offLabel: string;
|
||||
|
|
|
@ -114,6 +114,7 @@ define([], function () {
|
|||
showMore: "mer",
|
||||
recurrenceEventLabel: "Återkommande händelse",
|
||||
editRecurrenceSeries: "Redigera serie",
|
||||
allDayEventLabel: "All Day Event ?",
|
||||
ifRecurrenceLabel: "Återkommande ?",
|
||||
onLabel: "På",
|
||||
offLabel: "Av",
|
||||
|
|
|
@ -44,6 +44,14 @@ Site Url of library | Text| yes|
|
|||
Picture Library| Choice/Dropdown | yes| this is filled with all Picture Libraries (BaseTemplate : 109)
|
||||
number images to load | number| yes | number between 1 and 200
|
||||
|
||||
### react-slick Props
|
||||
|
||||
For all available props, go [here](https://react-slick.neostack.com/docs/api/).
|
||||
|
||||
### react-slick Methods
|
||||
|
||||
For all available methods, go [here](https://react-slick.neostack.com/docs/api#methods)
|
||||
|
||||
## Solution
|
||||
|
||||
The web part Use PnPjs library, Microsoft Graph API, Office-ui-fabric-react components, react-slick Component
|
||||
|
|
|
@ -1,74 +1,74 @@
|
|||
@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';
|
||||
|
||||
.carousel {
|
||||
.container {
|
||||
max-width: 700px;
|
||||
margin: 0px auto;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
.row {
|
||||
@include ms-Grid-row;
|
||||
@include ms-fontColor-white;
|
||||
background-color: $ms-color-themeDark;
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.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;
|
||||
.container {
|
||||
max-width: 700px;
|
||||
margin: 0px auto;
|
||||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.row {
|
||||
@include ms-Grid-row;
|
||||
@include ms-fontColor-white;
|
||||
background-color: $ms-color-themeDark;
|
||||
padding: 20px;
|
||||
}
|
||||
.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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
:global {
|
||||
.slick-next,
|
||||
.slick-prev {
|
||||
background: $ms-color-themePrimary !important;
|
||||
}
|
||||
.slick-dots {
|
||||
position: initial !important;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -173,7 +173,7 @@ export default class Carousel extends React.Component<ICarouselProps, ICarouselS
|
|||
}
|
||||
public render(): React.ReactElement<ICarouselProps> {
|
||||
const sliderSettings = {
|
||||
dots: false,
|
||||
dots: true,
|
||||
infinite: true,
|
||||
speed: 500,
|
||||
slidesToShow: 1,
|
||||
|
@ -181,7 +181,7 @@ export default class Carousel extends React.Component<ICarouselProps, ICarouselS
|
|||
lazyLoad: 'progressive',
|
||||
autoplaySpeed: 3000,
|
||||
initialSlide: this.state.photoIndex,
|
||||
arrows: false,
|
||||
arrows: true,
|
||||
draggable: true,
|
||||
adaptiveHeight: true,
|
||||
useCSS: true,
|
||||
|
@ -216,7 +216,7 @@ export default class Carousel extends React.Component<ICarouselProps, ICarouselS
|
|||
<Label style={{ width: '250px', margin: 'auto', fontSize: FontSizes.size20 }}>No images in the library</Label>
|
||||
</div>
|
||||
:
|
||||
<div style={{ width: '100%', height: '100%', overflow: 'hidden' }}>
|
||||
<div style={{ width: '100%', height: '100%'}}>
|
||||
|
||||
<div style={{ width: '100%'}}>
|
||||
<Slider
|
||||
|
|
|
@ -33,7 +33,6 @@
|
|||
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
|
||||
![SPFx 1.11](https://img.shields.io/badge/version-1.11-green.svg)
|
||||
|
||||
## Applies to
|
||||
|
@ -47,21 +46,18 @@
|
|||
|
||||
Property |Type|Required| comments
|
||||
--------------------|----|--------|----------
|
||||
Title | Text| no|WebPart Title
|
||||
searchFirstName | boolean|no| Lastname or Firstname search query
|
||||
Properties to search | text | no | By default **FirstName,LastName,WorkEmail,Department** are used for search. You can add custom properties separated by comma.
|
||||
Results per page | number | Number of people result to be displayed per page. Max of **20** is allowed, default of **10** is set.
|
||||
|
||||
|
||||
|
||||
Title | Text| No|WebPart Title
|
||||
searchFirstName | boolean|No| Lastname or Firstname search query
|
||||
Properties to search | text | No | By default **FirstName,LastName,WorkEmail,Department** are used for search. You can add custom properties separated by comma.
|
||||
Properties to sent as clear text | text | No | By default if the search key has empty spaces, its replaced with **+** before sending it to the search query. The search properties mentioned here will be sent without the empty space replacemnt.
|
||||
Results per page | number | Yes | Number of people result to be displayed per page. Max of **20** is allowed, default of **10** is set.
|
||||
|
||||
## Solution
|
||||
|
||||
The web part use PnPjs library, Office-ui-fabric-react components
|
||||
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
Directory Web Part| João Mendes
|
||||
Directory Web Part|João Mendes
|
||||
Directory Web Part| Peter Paul Kirschner ([@petkir_at](https://twitter.com/petkir_at))
|
||||
Directory Web Part| Sudharsan K ([@sudharsank](https://twitter.com/sudharsank))
|
||||
|
||||
|
@ -71,7 +67,8 @@ Version|Date|Comments
|
|||
-------|----|--------
|
||||
1.0.0|July 29, 2019|Initial release
|
||||
1.0.1|July 19, 2020|Bugfix and mock-service for workbench (```LivePersonaCard``` not supported in workbench)
|
||||
2.0.0|Sep 18 2020|React hooks, paging, dynamic search props, result alignment using office ui fabric stack.
|
||||
2.0.0.0|Sep 18 2020|React hooks, paging, dynamic search props, result alignment using office ui fabric stack.
|
||||
3.0.0.0|Oct 17 2020|Minor fixes and add the additional web part property.
|
||||
|
||||
|
||||
## Disclaimer
|
||||
|
@ -89,8 +86,4 @@ Version|Date|Comments
|
|||
- `gulp package-solution --ship`
|
||||
- `Add to AppCatalog and deploy`
|
||||
|
||||
|
||||
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-directory" />
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
},
|
||||
"name": "Search Directory",
|
||||
"id": "5b62bc16-3a71-461d-be2f-16bfcb011e8a",
|
||||
"version": "2.0.0.0",
|
||||
"version": "3.0.0.0",
|
||||
"includeClientSideAssets": true,
|
||||
"skipFeatureDeployment": true,
|
||||
"isDomainIsolated": false
|
||||
|
|
|
@ -19,6 +19,7 @@ export interface IDirectoryWebPartProps {
|
|||
title: string;
|
||||
searchFirstName: boolean;
|
||||
searchProps: string;
|
||||
clearTextSearchProps: string;
|
||||
pageSize: number;
|
||||
}
|
||||
|
||||
|
@ -47,6 +48,7 @@ export default class DirectoryWebPart extends BaseClientSideWebPart<
|
|||
this.properties.title = value;
|
||||
},
|
||||
searchProps: this.properties.searchProps,
|
||||
clearTextSearchProps: this.properties.clearTextSearchProps,
|
||||
pageSize: this.properties.pageSize
|
||||
}
|
||||
);
|
||||
|
@ -91,6 +93,13 @@ export default class DirectoryWebPart extends BaseClientSideWebPart<
|
|||
multiline: false,
|
||||
resizable: false
|
||||
}),
|
||||
PropertyPaneTextField('clearTextSearchProps', {
|
||||
label: strings.ClearTextSearchPropsLabel,
|
||||
description: strings.ClearTextSearchPropsDesc,
|
||||
value: this.properties.clearTextSearchProps,
|
||||
multiline: false,
|
||||
resizable: false
|
||||
}),
|
||||
PropertyPaneSlider('pageSize', {
|
||||
label: 'Results per page',
|
||||
showValue: true,
|
||||
|
|
|
@ -19,6 +19,7 @@ import { IDirectoryProps } from './IDirectoryProps';
|
|||
import Paging from './Pagination/Paging';
|
||||
|
||||
const slice: any = require('lodash/slice');
|
||||
const filter: any = require('lodash/filter');
|
||||
const wrapStackTokens: IStackTokens = { childrenGap: 30 };
|
||||
|
||||
const DirectoryHook: React.FC<IDirectoryProps> = (props) => {
|
||||
|
@ -131,11 +132,36 @@ const DirectoryHook: React.FC<IDirectoryProps> = (props) => {
|
|||
props.searchProps.split(',') : ['FirstName', 'LastName', 'WorkEmail', 'Department'];
|
||||
let qryText: string = '';
|
||||
let finalSearchText: string = searchText ? searchText.replace(/ /g, '+') : searchText;
|
||||
searchProps.map((srchprop, index) => {
|
||||
if (index == searchProps.length - 1)
|
||||
qryText += `${srchprop}:${finalSearchText}*`;
|
||||
else qryText += `${srchprop}:${finalSearchText}* OR `;
|
||||
});
|
||||
if (props.clearTextSearchProps) {
|
||||
let tmpCTProps: string[] = props.clearTextSearchProps.indexOf(',') >= 0 ? props.clearTextSearchProps.split(',') : [props.clearTextSearchProps];
|
||||
if (tmpCTProps.length > 0) {
|
||||
searchProps.map((srchprop, index) => {
|
||||
let ctPresent: any[] = filter(tmpCTProps, (o) => { return o.toLowerCase() == srchprop.toLowerCase(); });
|
||||
if (ctPresent.length > 0) {
|
||||
if(index == searchProps.length - 1) {
|
||||
qryText += `${srchprop}:${searchText}*`;
|
||||
} else qryText += `${srchprop}:${searchText}* OR `;
|
||||
} else {
|
||||
if(index == searchProps.length - 1) {
|
||||
qryText += `${srchprop}:${finalSearchText}*`;
|
||||
} else qryText += `${srchprop}:${finalSearchText}* OR `;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
searchProps.map((srchprop, index) => {
|
||||
if (index == searchProps.length - 1)
|
||||
qryText += `${srchprop}:${finalSearchText}*`;
|
||||
else qryText += `${srchprop}:${finalSearchText}* OR `;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
searchProps.map((srchprop, index) => {
|
||||
if (index == searchProps.length - 1)
|
||||
qryText += `${srchprop}:${finalSearchText}*`;
|
||||
else qryText += `${srchprop}:${finalSearchText}* OR `;
|
||||
});
|
||||
}
|
||||
console.log(qryText);
|
||||
const users = await _services.searchUsersNew('', qryText, false);
|
||||
setstate({
|
||||
...state,
|
||||
|
@ -252,12 +278,10 @@ const DirectoryHook: React.FC<IDirectoryProps> = (props) => {
|
|||
}, [state.users, props.pageSize]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("Alpha change");
|
||||
if (alphaKey.length > 0 && alphaKey != "0") _searchByAlphabets(false);
|
||||
}, [alphaKey]);
|
||||
|
||||
useEffect(() => {
|
||||
console.log("yes");
|
||||
_loadAlphabets();
|
||||
_searchByAlphabets(true);
|
||||
}, [props]);
|
||||
|
|
|
@ -7,5 +7,6 @@ export interface IDirectoryProps {
|
|||
searchFirstName: boolean;
|
||||
updateProperty: (value: string) => void;
|
||||
searchProps?: string;
|
||||
clearTextSearchProps?: string;
|
||||
pageSize?: number;
|
||||
}
|
||||
|
|
|
@ -10,6 +10,8 @@ define([], function() {
|
|||
"LoadingText": "Searching for user. Please wait...",
|
||||
"SearchPropsLabel": "Properties to search",
|
||||
"SearchPropsDesc": "Enter the properties separated by comma to be used for search",
|
||||
"ClearTextSearchPropsLabel":"Properties whose values are not replaced",
|
||||
"ClearTextSearchPropsDesc":"Enter the properties separated by comma to be sent as it is without replacing space with '+'",
|
||||
"PagingLabel": "Results per page"
|
||||
}
|
||||
});
|
||||
|
|
|
@ -9,6 +9,8 @@ declare interface IDirectoryWebPartStrings {
|
|||
LoadingText: string;
|
||||
SearchPropsLabel: string;
|
||||
SearchPropsDesc: string;
|
||||
ClearTextSearchPropsLabel: string;
|
||||
ClearTextSearchPropsDesc: string;
|
||||
PagingLabel: string;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,12 @@
|
|||
{
|
||||
"resource": "Microsoft Graph",
|
||||
"scope": "Directory.AccessAsUser.All"
|
||||
},
|
||||
{
|
||||
"resource": "Microsoft Graph",
|
||||
"scope": "User.Read"
|
||||
}
|
||||
|
||||
]
|
||||
},
|
||||
"paths": {
|
||||
|
|
|
@ -59,6 +59,8 @@ react-outlook-add-todo-task|Luis Mañez (MVP, [ClearPeople](http://www.clearpeop
|
|||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0.0|Jun 3, 2020|Initial release
|
||||
1.1.0|Sep 3, 2020|To Do item body coming from email body
|
||||
1.2.0|Oct 16, 2020|To Do item body included a "open in outlook" link
|
||||
|
||||
## Disclaimer
|
||||
|
||||
|
|
|
@ -162,8 +162,8 @@ export default class CreateTask extends React.Component<
|
|||
status: "notStarted",
|
||||
title: taskTitle,
|
||||
body: {
|
||||
content: this.props.context.item.body,
|
||||
contentType: "text",
|
||||
content: this._composeBody(this.props.context.item.body),
|
||||
contentType: "html",
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -180,4 +180,10 @@ export default class CreateTask extends React.Component<
|
|||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
private _composeBody(emailBody: string): string {
|
||||
const id: string = encodeURIComponent(this.props.context.item.id);
|
||||
const link: string = `<a href='https://outlook.office365.com/owa/?ItemID=${id}&exvsurl=1&viewmodel=ReadMessageItem'>Open in Outlook</a>`;
|
||||
return `${emailBody}<p style='font-size: large; padding-top: 10px;'>${link}</p>`;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
"environment": "spo",
|
||||
"framework": "react",
|
||||
"isCreatingSolution": true,
|
||||
"version": "1.10.0",
|
||||
"version": "1.11.0",
|
||||
"libraryName": "react-personal-greeting",
|
||||
"libraryId": "5e7ea24d-fccc-4d96-a56c-488564d9c61c",
|
||||
"packageManager": "npm",
|
||||
|
|
|
@ -8,7 +8,7 @@ The web part pulls in the current user's name and displays it on the page. The g
|
|||
|
||||
## Used SharePoint Framework Version
|
||||
|
||||
![1.10.0](https://img.shields.io/badge/version-1.10.0-green.svg)
|
||||
![1.11.0](https://img.shields.io/badge/version-1.11.0-green.svg)
|
||||
|
||||
## Applies to
|
||||
|
||||
|
@ -30,6 +30,7 @@ react-personal-greeting|Zach Roberts - [SPODev](https://spodev.com)
|
|||
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.1|September 24, 2020| Updated SPFX version and added font-size
|
||||
1.0|April 14, 2020|Initial release
|
||||
|
||||
## Disclaimer
|
||||
|
@ -46,8 +47,8 @@ Version|Date|Comments
|
|||
* `gulp build`
|
||||
* `gulp bundle --ship`
|
||||
* `gulp package-solution --ship`
|
||||
* add the webpart to your tenant app store
|
||||
* add the app to a SharePoint site and then add the webpart to the page
|
||||
* add the web part to your tenant app store
|
||||
* add the app to a SharePoint site and then add the web part to the page
|
||||
|
||||
|
||||
## Features
|
||||
|
@ -55,8 +56,8 @@ Version|Date|Comments
|
|||
This Web Part illustrates the following concepts on top of the SharePoint Framework:
|
||||
|
||||
* Using the SPFx context to gather the current user's display name.
|
||||
* Adjusting the styles of the component in the webpart using the props adjusted through the property pane.
|
||||
* PnP SPFx Placeholder - This component allows you to have a placeholder visble under certain conditions if your web parts requires some setup.
|
||||
* PnP SPFx Color Picker - This component adds an awesome color picker to the property pane, great for adjusting colors in your webpart.
|
||||
* Adjusting the styles of the component in the web part using the props adjusted through the property pane.
|
||||
* PnP SPFx Placeholder - This component allows you to have a placeholder visible under certain conditions if your web parts requires some setup.
|
||||
* PnP SPFx Color Picker - This component adds an awesome color picker to the property pane, great for adjusting colors in your web part.
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-personal-greeting" />
|
||||
|
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 2.0 MiB |
|
@ -3,9 +3,16 @@
|
|||
"solution": {
|
||||
"name": "react-personal-greeting-client-side-solution",
|
||||
"id": "5e7ea24d-fccc-4d96-a56c-488564d9c61c",
|
||||
"version": "1.0.0.0",
|
||||
"version": "1.1.0.0",
|
||||
"includeClientSideAssets": true,
|
||||
"isDomainIsolated": false
|
||||
"isDomainIsolated": false,
|
||||
"developer": {
|
||||
"name": "",
|
||||
"mpnId": "",
|
||||
"privacyUrl": "",
|
||||
"termsOfUseUrl": "",
|
||||
"websiteUrl": ""
|
||||
}
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/react-personal-greeting.sppkg"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "react-personal-greeting",
|
||||
"version": "0.0.1",
|
||||
"version": "1.1.0",
|
||||
"private": true,
|
||||
"main": "lib/index.js",
|
||||
"engines": {
|
||||
|
@ -14,19 +14,15 @@
|
|||
"postversion": "gulp dist"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft/sp-core-library": "1.10.0",
|
||||
"@microsoft/sp-lodash-subset": "1.10.0",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.10.0",
|
||||
"@microsoft/sp-property-pane": "1.10.0",
|
||||
"@microsoft/sp-webpart-base": "1.10.0",
|
||||
"@microsoft/sp-core-library": "1.11.0",
|
||||
"@microsoft/sp-lodash-subset": "1.11.0",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.11.0",
|
||||
"@microsoft/sp-property-pane": "1.11.0",
|
||||
"@microsoft/sp-webpart-base": "1.11.0",
|
||||
"@pnp/pnpjs": "^2.0.3",
|
||||
"@pnp/spfx-controls-react": "1.17.0",
|
||||
"@pnp/spfx-property-controls": "1.17.0",
|
||||
"@types/es6-promise": "0.0.33",
|
||||
"@types/react": "16.8.8",
|
||||
"@types/react-dom": "16.8.3",
|
||||
"@types/webpack-env": "1.13.1",
|
||||
"office-ui-fabric-react": "6.189.2",
|
||||
"office-ui-fabric-react": "6.214.0",
|
||||
"react": "16.8.5",
|
||||
"react-dom": "16.8.5"
|
||||
},
|
||||
|
@ -36,10 +32,10 @@
|
|||
"devDependencies": {
|
||||
"@microsoft/microsoft-graph-types": "^1.12.0",
|
||||
"@microsoft/rush-stack-compiler-3.3": "0.3.5",
|
||||
"@microsoft/sp-build-web": "1.10.0",
|
||||
"@microsoft/sp-module-interfaces": "1.10.0",
|
||||
"@microsoft/sp-tslint-rules": "1.10.0",
|
||||
"@microsoft/sp-webpart-workbench": "1.10.0",
|
||||
"@microsoft/sp-build-web": "1.11.0",
|
||||
"@microsoft/sp-module-interfaces": "1.11.0",
|
||||
"@microsoft/sp-tslint-rules": "1.11.0",
|
||||
"@microsoft/sp-webpart-workbench": "1.11.0",
|
||||
"@types/chai": "3.4.34",
|
||||
"@types/mocha": "2.2.38",
|
||||
"ajv": "~5.2.2",
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
"group": { "default": "Other" },
|
||||
"title": { "default": "Personal Greeting" },
|
||||
"description": { "default": "Personal Greeting description" },
|
||||
"officeFabricIconFontName": "Page",
|
||||
"officeFabricIconFontName": "TextDocumentShared",
|
||||
"properties": {
|
||||
"description": "Personal Greeting"
|
||||
}
|
||||
|
|
|
@ -4,11 +4,11 @@ import { Version } from '@microsoft/sp-core-library';
|
|||
import {
|
||||
IPropertyPaneConfiguration,
|
||||
PropertyPaneTextField,
|
||||
PropertyPaneDropdown
|
||||
PropertyPaneDropdown,
|
||||
IPropertyPaneDropdownOption
|
||||
} from '@microsoft/sp-property-pane';
|
||||
import { BaseClientSideWebPart, WebPartContext } from '@microsoft/sp-webpart-base';
|
||||
|
||||
import * as strings from 'PersonalGreetingWebPartStrings';
|
||||
import PersonalGreeting from './components/PersonalGreeting';
|
||||
import { IPersonalGreetingProps } from './components/IPersonalGreetingProps';
|
||||
import { PropertyFieldColorPicker, PropertyFieldColorPickerStyle } from '@pnp/spfx-property-controls/lib/PropertyFieldColorPicker';
|
||||
|
@ -18,8 +18,56 @@ export interface IPersonalGreetingWebPartProps {
|
|||
context: WebPartContext;
|
||||
position: string;
|
||||
textColor: string;
|
||||
fontSize: number;
|
||||
}
|
||||
|
||||
const fontSizeOptions: IPropertyPaneDropdownOption[] = [
|
||||
{
|
||||
key: 12,
|
||||
text: '12'
|
||||
},
|
||||
{
|
||||
key: 14,
|
||||
text: '16'
|
||||
},
|
||||
{
|
||||
key: 18,
|
||||
text: '18'
|
||||
},
|
||||
{
|
||||
key: 20,
|
||||
text: '20'
|
||||
},
|
||||
{
|
||||
key: 24,
|
||||
text: '24'
|
||||
},
|
||||
{
|
||||
key: 28,
|
||||
text: '28'
|
||||
},
|
||||
{
|
||||
key: 32,
|
||||
text: '32'
|
||||
},
|
||||
{
|
||||
key: 36,
|
||||
text: '36'
|
||||
},
|
||||
{
|
||||
key: 42,
|
||||
text: '42'
|
||||
},
|
||||
{
|
||||
key: 46,
|
||||
text: '46'
|
||||
},
|
||||
{
|
||||
key: 68,
|
||||
text: '68'
|
||||
},
|
||||
];
|
||||
|
||||
export default class PersonalGreetingWebPart extends BaseClientSideWebPart <IPersonalGreetingWebPartProps> {
|
||||
|
||||
public render(): void {
|
||||
|
@ -29,7 +77,8 @@ export default class PersonalGreetingWebPart extends BaseClientSideWebPart <IPer
|
|||
greetingText: this.properties.greetingText,
|
||||
context: this.context,
|
||||
position: this.properties.position,
|
||||
textColor: this.properties.textColor
|
||||
textColor: this.properties.textColor,
|
||||
fontSize: this.properties.fontSize
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -76,6 +125,11 @@ export default class PersonalGreetingWebPart extends BaseClientSideWebPart <IPer
|
|||
}
|
||||
]
|
||||
}),
|
||||
PropertyPaneDropdown('fontSize', {
|
||||
label: 'Font Size',
|
||||
options: fontSizeOptions,
|
||||
selectedKey: 20
|
||||
}),
|
||||
PropertyFieldColorPicker('textColor', {
|
||||
label: 'Text Color',
|
||||
properties: this.properties,
|
||||
|
|
|
@ -6,4 +6,5 @@ export interface IPersonalGreetingProps {
|
|||
context: WebPartContext;
|
||||
position: string;
|
||||
textColor: string;
|
||||
fontSize: number;
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.2), 0 25px 50px 0 rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
.title {
|
||||
font-size: x-large;
|
||||
font-weight: 375;
|
||||
}
|
||||
}
|
|
@ -1,25 +1,22 @@
|
|||
import * as React from 'react';
|
||||
import styles from './PersonalGreeting.module.scss';
|
||||
import { IPersonalGreetingProps } from './IPersonalGreetingProps';
|
||||
import { escape } from '@microsoft/sp-lodash-subset';
|
||||
import { CommandBar, ICommandBarItemProps } from 'office-ui-fabric-react/lib/CommandBar';
|
||||
import { Placeholder } from "@pnp/spfx-controls-react/lib/Placeholder";
|
||||
|
||||
|
||||
export default class PersonalGreeting extends React.Component<IPersonalGreetingProps, {}> {
|
||||
public render(): React.ReactElement<IPersonalGreetingProps> {
|
||||
|
||||
const custstyles = {
|
||||
const custStyles = {
|
||||
'text-align': this.props.position,
|
||||
'color': this.props.textColor
|
||||
'color': this.props.textColor,
|
||||
'fontSize': this.props.fontSize
|
||||
} as React.CSSProperties;
|
||||
|
||||
return (
|
||||
<div className={ styles.personalGreeting }>
|
||||
{this.props.greetingText == null ?
|
||||
<Placeholder iconName='Edit' iconText='Configure the web part' description='Please configure the web part' buttonLabel='Configure' onConfigure={this._onConfigure} />
|
||||
: <div className={ styles.title } style={custstyles}>{this.props.greetingText} {this.props.context.pageContext.user.displayName}</div>
|
||||
// : <h2>{this.props.greetingText} {this.props.context.pageContext.user.displayName} </h2>
|
||||
: <div className={ styles.title } style={custStyles}>{this.props.greetingText} {this.props.context.pageContext.user.displayName}</div>
|
||||
}
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -30,7 +30,8 @@
|
|||
"esModuleInterop": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"@microsoft/generator-sharepoint": {
|
||||
"isCreatingSolution": true,
|
||||
"environment": "spo",
|
||||
"version": "1.10.0",
|
||||
"version": "1.11.0",
|
||||
"libraryName": "react-simple-poll",
|
||||
"libraryId": "890ced10-dacc-4d0d-b9df-355a289980b3",
|
||||
"packageManager": "npm",
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# React Quick Poll
|
||||
|
||||
## Summary
|
||||
|
||||
> This component is developed for the users who really need to create a **_Poll_** within a minute and with less maintenance. **_'QuickPoll'_** list will be created automatically to store the user response.
|
||||
> Following are some of the features of this component.
|
||||
* **_Easy_** to setup with most of the configurations are optional.
|
||||
|
@ -22,7 +23,7 @@
|
|||
* **_Start Date_** - Date when the end user can start seeing the poll question.
|
||||
* **_End Date_** - Last day of the poll question visible to the end user.
|
||||
|
||||
3. **_Success Message_** - Message to be displayed to the user after successful submission. It is optional, if not provided the default message '**Thank you for your submission**' will be displayed.
|
||||
3. **_Success Message_** - Message to be displayed to the user after a successful submission. It is optional, if not provided the default message '**Thank you for your submission**' will be displayed.
|
||||
|
||||
4. **_Response Message_** - Message to be displayed to the user with the user response, once the user has submitted. It is optional, if not provided the default message '**You voted for: ~User Response~**' will be displayed below the chart.
|
||||
|
||||
|
@ -36,33 +37,37 @@
|
|||
* Make sure the **Multi Choice** option is chosen wisely, do not change once the user started to response to the poll.
|
||||
|
||||
## Preview
|
||||
![Advanced-Comments-Box](./assets/react-quick-poll.gif)
|
||||
|
||||
![React-Quick-Poll](./assets/react-quick-poll.gif)
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
![drop](https://img.shields.io/badge/version-GA-green.svg)
|
||||
|
||||
![SPFx 1.11](https://img.shields.io/badge/version-1.11-green.svg)
|
||||
|
||||
## Applies to
|
||||
|
||||
* [SharePoint Framework](https://docs.microsoft.com/sharepoint/dev/spfx/sharepoint-framework-overview)
|
||||
* [Office 365 tenant](https://docs.microsoft.com/sharepoint/dev/spfx/set-up-your-development-environment)
|
||||
* [SharePoint Framework](https:/dev.office.com/sharepoint)
|
||||
* [Office 365 tenant](https://dev.office.com/sharepoint/docs/spfx/set-up-your-development-environment)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
> **@microsoft/generator-sharepoint - 1.10.0**
|
||||
> **@microsoft/generator-sharepoint - 1.11.0**
|
||||
|
||||
## Solution
|
||||
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
react-quick-poll | Sudharsan K.([@sudharsank](https://twitter.com/sudharsank), [Know More](http://windowssharepointserver.blogspot.com/))
|
||||
react-quick-poll | Sudharsan K.([@sudharsank](https://twitter.com/sudharsank), [Know More](https://spknowledge.com/))
|
||||
|
||||
## Version history
|
||||
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0.0.1|Feb 24 2020|Initial release
|
||||
2.0.0.0|Oct 17 2020|Initial release
|
||||
|
||||
## 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.**
|
||||
|
||||
## Minimal Path to Awesome
|
||||
|
@ -71,26 +76,27 @@ Version|Date|Comments
|
|||
- in the command line run:
|
||||
- `npm install`
|
||||
- `gulp bundle --ship && gulp package-solution --ship`
|
||||
- Add the .sppkg file to the app catalog and add the **'_Quick Poll_'** web part to the page.
|
||||
- Add the `.sppkg` file to the app catalog and add the **'_Quick Poll_'** web part to the page.
|
||||
|
||||
## Features
|
||||
|
||||
- Used [PnP Property Pane Controls](https://sharepoint.github.io/sp-dev-fx-property-controls/) to create the property pane controls
|
||||
* [PropertyFieldToggleWithCallout](https://sharepoint.github.io/sp-dev-fx-property-controls/controls/PropertyFieldToggleWithCallout/)
|
||||
* [PropertyFieldCollectionData](https://sharepoint.github.io/sp-dev-fx-property-controls/controls/PropertyFieldCollectionData/)
|
||||
* [PropertyFieldChoiceGroupWithCallout](https://sharepoint.github.io/sp-dev-fx-property-controls/controls/PropertyFieldChoiceGroupWithCallout/)
|
||||
* PropertyPaneTextField (From base property controls)
|
||||
- Used [PnP Reusable REact Controls](https://sharepoint.github.io/sp-dev-fx-controls-react/)
|
||||
- Used [PnP Reusable React Controls](https://sharepoint.github.io/sp-dev-fx-controls-react/)
|
||||
* [Placeholder](https://sharepoint.github.io/sp-dev-fx-controls-react/controls/Placeholder/)
|
||||
* [ChartControl](https://sharepoint.github.io/sp-dev-fx-controls-react/controls/ChartControl/)
|
||||
- Used few styles and controls (Text, MessageBar, ProgressIndicator, PrimaryButton, ChoiceGroup, List, Checkbox) from [Office UI Fabric](https://developer.microsoft.com/en-us/fabric)
|
||||
- Used [PnP](https://pnp.github.io/pnpjs/) for communication with SharePoint.
|
||||
- Used [Moment.js](https://momentjs.com/) for datetime formatting.
|
||||
|
||||
#### Local Mode
|
||||
### Local Mode
|
||||
|
||||
This solution doesn't work on local mode.
|
||||
|
||||
#### SharePoint Mode
|
||||
### SharePoint Mode
|
||||
|
||||
If you want to try on a real environment, open:
|
||||
[O365 Workbench](https://your-domain.sharepoint.com/_layouts/15/workbench.aspx)
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-quick-poll" />
|
||||
|
|
|
@ -3,9 +3,16 @@
|
|||
"solution": {
|
||||
"name": "React Quick Poll",
|
||||
"id": "890ced10-dacc-4d0d-b9df-355a289980b3",
|
||||
"version": "1.0.0.1",
|
||||
"version": "2.0.0.0",
|
||||
"includeClientSideAssets": true,
|
||||
"isDomainIsolated": false
|
||||
"isDomainIsolated": false,
|
||||
"developer": {
|
||||
"name": "Sudharsan K.",
|
||||
"privacyUrl": "",
|
||||
"termsOfUseUrl": "",
|
||||
"websiteUrl": "https://spknowledge.com/",
|
||||
"mpnId": "000000"
|
||||
}
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/react-quick-poll.sppkg"
|
||||
|
|
|
@ -12,20 +12,17 @@
|
|||
"test": "gulp test"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft/sp-core-library": "1.10.0",
|
||||
"@microsoft/sp-lodash-subset": "1.10.0",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.10.0",
|
||||
"@microsoft/sp-property-pane": "1.10.0",
|
||||
"@microsoft/sp-webpart-base": "1.10.0",
|
||||
"@microsoft/sp-core-library": "1.11.0",
|
||||
"@microsoft/sp-lodash-subset": "1.11.0",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.11.0",
|
||||
"@microsoft/sp-property-pane": "1.11.0",
|
||||
"@microsoft/sp-webpart-base": "1.11.0",
|
||||
"@pnp/polyfill-ie11": "^2.0.1-5",
|
||||
"@pnp/sp": "^2.0.2",
|
||||
"@pnp/spfx-controls-react": "^1.16.0",
|
||||
"@pnp/spfx-property-controls": "^1.16.0",
|
||||
"@types/es6-promise": "0.0.33",
|
||||
"@types/react": "16.8.8",
|
||||
"@types/react-dom": "16.8.3",
|
||||
"@types/webpack-env": "1.13.1",
|
||||
"moment": "^2.24.0",
|
||||
"office-ui-fabric-react": "6.189.2",
|
||||
"office-ui-fabric-react": "6.214.0",
|
||||
"react": "16.8.5",
|
||||
"react-dom": "16.8.5"
|
||||
},
|
||||
|
@ -33,14 +30,14 @@
|
|||
"@types/react": "16.8.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/sp-build-web": "1.10.0",
|
||||
"@microsoft/sp-tslint-rules": "1.10.0",
|
||||
"@microsoft/sp-module-interfaces": "1.10.0",
|
||||
"@microsoft/sp-webpart-workbench": "1.10.0",
|
||||
"@microsoft/rush-stack-compiler-3.3": "0.3.5",
|
||||
"gulp": "~3.9.1",
|
||||
"@microsoft/sp-build-web": "1.11.0",
|
||||
"@microsoft/sp-module-interfaces": "1.11.0",
|
||||
"@microsoft/sp-tslint-rules": "1.11.0",
|
||||
"@microsoft/sp-webpart-workbench": "1.11.0",
|
||||
"@types/chai": "3.4.34",
|
||||
"@types/mocha": "2.2.38",
|
||||
"ajv": "~5.2.2"
|
||||
"ajv": "~5.2.2",
|
||||
"gulp": "~3.9.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,8 +2,8 @@ import * as React from 'react';
|
|||
import * as ReactDom from 'react-dom';
|
||||
import { Version, ServiceScope } from '@microsoft/sp-core-library';
|
||||
import {
|
||||
IPropertyPaneConfiguration,
|
||||
PropertyPaneTextField,
|
||||
IPropertyPaneConfiguration,
|
||||
PropertyPaneTextField,
|
||||
} from '@microsoft/sp-property-pane';
|
||||
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
|
||||
import { CalloutTriggers } from '@pnp/spfx-property-controls/lib/PropertyFieldHeader';
|
||||
|
@ -11,6 +11,7 @@ import { PropertyFieldToggleWithCallout } from '@pnp/spfx-property-controls/lib/
|
|||
import { PropertyFieldChoiceGroupWithCallout } from '@pnp/spfx-property-controls/lib/PropertyFieldChoiceGroupWithCallout';
|
||||
import { PropertyFieldCollectionData, CustomCollectionFieldType } from '@pnp/spfx-property-controls/lib/PropertyFieldCollectionData';
|
||||
import { DateTimePicker, DateConvention, TimeConvention } from '@pnp/spfx-controls-react/lib/DateTimePicker';
|
||||
import "@pnp/polyfill-ie11";
|
||||
import { sp } from "@pnp/sp/presets/all";
|
||||
import * as strings from 'SimplePollWebPartStrings';
|
||||
import SimplePoll from './components/SimplePoll';
|
||||
|
@ -21,262 +22,265 @@ import { ChartType } from '@pnp/spfx-controls-react/lib/ChartControl';
|
|||
|
||||
|
||||
export interface ISimplePollWebPartProps {
|
||||
pollQuestions: any[];
|
||||
MsgAfterSubmission: string;
|
||||
BtnSubmitVoteText: string;
|
||||
chartType: ChartType;
|
||||
ResponseMsgToUser: string;
|
||||
pollBasedOnDate: boolean;
|
||||
NoPollMsg: string;
|
||||
pollQuestions: any[];
|
||||
MsgAfterSubmission: string;
|
||||
BtnSubmitVoteText: string;
|
||||
chartType: ChartType;
|
||||
ResponseMsgToUser: string;
|
||||
pollBasedOnDate: boolean;
|
||||
NoPollMsg: string;
|
||||
}
|
||||
|
||||
export default class SimplePollWebPart extends BaseClientSideWebPart<ISimplePollWebPartProps> {
|
||||
private helper: SPHelper = null;
|
||||
private userinfo: IUserInfo = null;
|
||||
protected async onInit(): Promise<void> {
|
||||
await super.onInit();
|
||||
sp.setup(this.context);
|
||||
this.helper = new SPHelper();
|
||||
this.userinfo = await this.helper.getCurrentUserInfo();
|
||||
}
|
||||
private helper: SPHelper = null;
|
||||
private userinfo: IUserInfo = null;
|
||||
protected async onInit(): Promise<void> {
|
||||
await super.onInit();
|
||||
sp.setup({
|
||||
ie11: true,
|
||||
spfxContext: this.context
|
||||
});
|
||||
this.helper = new SPHelper();
|
||||
this.userinfo = await this.helper.getCurrentUserInfo();
|
||||
}
|
||||
|
||||
public render(): void {
|
||||
const element: React.ReactElement<ISimplePollProps> = React.createElement(
|
||||
SimplePoll,
|
||||
{
|
||||
pollQuestions: this.properties.pollQuestions,
|
||||
SuccessfullVoteSubmissionMsg: this.properties.MsgAfterSubmission,
|
||||
ResponseMsgToUser: this.properties.ResponseMsgToUser,
|
||||
BtnSubmitVoteText: this.properties.BtnSubmitVoteText,
|
||||
chartType: this.properties.chartType ? this.properties.chartType : ChartType.Doughnut,
|
||||
pollBasedOnDate: this.properties.pollBasedOnDate,
|
||||
NoPollMsg: this.properties.NoPollMsg,
|
||||
currentUserInfo: this.userinfo,
|
||||
openPropertyPane: this.openPropertyPane
|
||||
}
|
||||
);
|
||||
|
||||
ReactDom.render(element, this.domElement);
|
||||
}
|
||||
|
||||
protected get disableReactivePropertyChanges() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected onDispose(): void {
|
||||
ReactDom.unmountComponentAtNode(this.domElement);
|
||||
}
|
||||
|
||||
protected get dataVersion(): Version {
|
||||
return Version.parse('1.0');
|
||||
}
|
||||
|
||||
private openPropertyPane = (): void => {
|
||||
this.context.propertyPane.open();
|
||||
}
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
header: {
|
||||
description: strings.PropertyPaneDescription
|
||||
},
|
||||
groups: [
|
||||
public render(): void {
|
||||
const element: React.ReactElement<ISimplePollProps> = React.createElement(
|
||||
SimplePoll,
|
||||
{
|
||||
groupName: strings.BasicGroupName,
|
||||
groupFields: [
|
||||
PropertyFieldToggleWithCallout('pollBasedOnDate', {
|
||||
calloutTrigger: CalloutTriggers.Hover,
|
||||
key: 'pollBasedOnDateFieldId',
|
||||
label: strings.PollDateLabel,
|
||||
calloutContent: React.createElement('div', {}, strings.PollDateCalloutText),
|
||||
onText: 'Yes',
|
||||
offText: 'No',
|
||||
checked: this.properties.pollBasedOnDate
|
||||
}),
|
||||
PropertyFieldCollectionData("pollQuestions", {
|
||||
key: "pollQuestions",
|
||||
label: strings.PollQuestionsLabel,
|
||||
panelHeader: strings.PollQuestionsPanelHeader,
|
||||
manageBtnLabel: strings.PollQuestionsManageButton,
|
||||
enableSorting: true,
|
||||
value: this.properties.pollQuestions,
|
||||
fields: [
|
||||
{
|
||||
id: "QTitle",
|
||||
title: strings.Q_Title_Title,
|
||||
type: CustomCollectionFieldType.custom,
|
||||
required: true,
|
||||
onCustomRender: (field, value, onUpdate, item, itemId) => {
|
||||
return (
|
||||
React.createElement("div", null,
|
||||
React.createElement("textarea",
|
||||
{
|
||||
style: { width: "250px", height: "70px" },
|
||||
placeholder: strings.Q_Title_Placeholder,
|
||||
key: itemId,
|
||||
value: value,
|
||||
onChange: (event: React.FormEvent<HTMLTextAreaElement>) => {
|
||||
onUpdate(field.id, event.currentTarget.value);
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "QOptions",
|
||||
title: strings.Q_Options_Title,
|
||||
type: CustomCollectionFieldType.custom,
|
||||
required: true,
|
||||
onCustomRender: (field, value, onUpdate, item, itemId) => {
|
||||
return (
|
||||
React.createElement("div", null,
|
||||
React.createElement("textarea",
|
||||
{
|
||||
style: { width: "250px", height: "70px" },
|
||||
placeholder: strings.Q_Options_Placeholder,
|
||||
key: itemId,
|
||||
value: value,
|
||||
onChange: (event: React.FormEvent<HTMLTextAreaElement>) => {
|
||||
onUpdate(field.id, event.currentTarget.value);
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "QMultiChoice",
|
||||
title: strings.MultiChoice_Title,
|
||||
type: CustomCollectionFieldType.boolean,
|
||||
defaultValue: false
|
||||
},
|
||||
{
|
||||
id: "QStartDate",
|
||||
title: strings.Q_StartDate_Title,
|
||||
type: CustomCollectionFieldType.custom,
|
||||
required: false,
|
||||
onCustomRender: (field, value, onUpdate, item, itemId) => {
|
||||
return (
|
||||
React.createElement(DateTimePicker, {
|
||||
key: itemId,
|
||||
showLabels: false,
|
||||
dateConvention: DateConvention.Date,
|
||||
showGoToToday: true,
|
||||
showMonthPickerAsOverlay: true,
|
||||
value: value ? new Date(value) : null,
|
||||
disabled: !this.properties.pollBasedOnDate,
|
||||
onChange: (date: Date) => {
|
||||
onUpdate(field.id, date);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "QEndDate",
|
||||
title: strings.Q_EndDate_Title,
|
||||
type: CustomCollectionFieldType.custom,
|
||||
required: false,
|
||||
onCustomRender: (field, value, onUpdate, item, itemId) => {
|
||||
return (
|
||||
React.createElement(DateTimePicker, {
|
||||
key: itemId,
|
||||
showLabels: false,
|
||||
dateConvention: DateConvention.Date,
|
||||
showGoToToday: true,
|
||||
showMonthPickerAsOverlay: true,
|
||||
value: value ? new Date(value) : null,
|
||||
disabled: !this.properties.pollBasedOnDate,
|
||||
onChange: (date: Date) => {
|
||||
onUpdate(field.id, date);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
],
|
||||
disabled: false
|
||||
}),
|
||||
PropertyPaneTextField('MsgAfterSubmission', {
|
||||
label: strings.MsgAfterSubmissionLabel,
|
||||
description: strings.MsgAfterSubmissionDescription,
|
||||
maxLength: 150,
|
||||
multiline: true,
|
||||
rows: 3,
|
||||
resizable: false,
|
||||
placeholder: strings.MsgAfterSubmissionPlaceholder,
|
||||
value: this.properties.MsgAfterSubmission
|
||||
}),
|
||||
PropertyPaneTextField('ResponseMsgToUser', {
|
||||
label: strings.ResponseMsgToUserLabel,
|
||||
description: strings.ResponseMsgToUserDescription,
|
||||
maxLength: 150,
|
||||
multiline: true,
|
||||
rows: 3,
|
||||
resizable: false,
|
||||
placeholder: strings.ResponseMsgToUserPlaceholder,
|
||||
value: this.properties.ResponseMsgToUser
|
||||
}),
|
||||
PropertyPaneTextField('BtnSubmitVoteText', {
|
||||
label: strings.BtnSumbitVoteLabel,
|
||||
description: strings.BtnSumbitVoteDescription,
|
||||
maxLength: 50,
|
||||
multiline: false,
|
||||
resizable: false,
|
||||
placeholder: strings.BtnSumbitVotePlaceholder,
|
||||
value: this.properties.BtnSubmitVoteText
|
||||
}),
|
||||
PropertyPaneTextField('NoPollMsg', {
|
||||
label: strings.NoPollMsgLabel,
|
||||
description: strings.NoPollMsgDescription,
|
||||
maxLength: 150,
|
||||
multiline: true,
|
||||
rows: 3,
|
||||
resizable: false,
|
||||
placeholder: strings.NoPollMsgPlaceholder,
|
||||
value: this.properties.NoPollMsg
|
||||
}),
|
||||
PropertyFieldChoiceGroupWithCallout('chartType', {
|
||||
calloutContent: React.createElement('div', {}, strings.ChartFieldCalloutText),
|
||||
calloutTrigger: CalloutTriggers.Hover,
|
||||
key: 'choice_charttype',
|
||||
label: strings.ChartFieldLabel,
|
||||
options: [
|
||||
{
|
||||
key: 'pie',
|
||||
text: 'Pie',
|
||||
checked: this.properties.chartType === ChartType.Pie,
|
||||
iconProps: { officeFabricIconFontName: 'PieSingle' }
|
||||
}, {
|
||||
key: 'doughnut',
|
||||
text: 'Doughnut',
|
||||
checked: this.properties.chartType === ChartType.Doughnut,
|
||||
iconProps: { officeFabricIconFontName: 'DonutChart' }
|
||||
}, {
|
||||
key: 'bar',
|
||||
text: 'Bar',
|
||||
checked: this.properties.chartType === ChartType.Bar,
|
||||
iconProps: { officeFabricIconFontName: 'BarChartVertical' }
|
||||
}, {
|
||||
key: 'horizontalBar',
|
||||
text: 'Horizontal Bar',
|
||||
checked: this.properties.chartType === ChartType.HorizontalBar,
|
||||
iconProps: { officeFabricIconFontName: 'BarChartHorizontal' }
|
||||
}, {
|
||||
key: 'line',
|
||||
text: 'Line',
|
||||
checked: this.properties.chartType === ChartType.Line,
|
||||
iconProps: { officeFabricIconFontName: 'LineChart' }
|
||||
}]
|
||||
})
|
||||
]
|
||||
pollQuestions: this.properties.pollQuestions,
|
||||
SuccessfullVoteSubmissionMsg: this.properties.MsgAfterSubmission,
|
||||
ResponseMsgToUser: this.properties.ResponseMsgToUser,
|
||||
BtnSubmitVoteText: this.properties.BtnSubmitVoteText,
|
||||
chartType: this.properties.chartType ? this.properties.chartType : ChartType.Doughnut,
|
||||
pollBasedOnDate: this.properties.pollBasedOnDate,
|
||||
NoPollMsg: this.properties.NoPollMsg,
|
||||
currentUserInfo: this.userinfo,
|
||||
openPropertyPane: this.openPropertyPane
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
ReactDom.render(element, this.domElement);
|
||||
}
|
||||
|
||||
protected get disableReactivePropertyChanges() {
|
||||
return false;
|
||||
}
|
||||
|
||||
protected onDispose(): void {
|
||||
ReactDom.unmountComponentAtNode(this.domElement);
|
||||
}
|
||||
|
||||
protected get dataVersion(): Version {
|
||||
return Version.parse('1.0');
|
||||
}
|
||||
|
||||
private openPropertyPane = (): void => {
|
||||
this.context.propertyPane.open();
|
||||
}
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
header: {
|
||||
description: strings.PropertyPaneDescription
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
groupName: strings.BasicGroupName,
|
||||
groupFields: [
|
||||
PropertyFieldToggleWithCallout('pollBasedOnDate', {
|
||||
calloutTrigger: CalloutTriggers.Hover,
|
||||
key: 'pollBasedOnDateFieldId',
|
||||
label: strings.PollDateLabel,
|
||||
calloutContent: React.createElement('div', {}, strings.PollDateCalloutText),
|
||||
onText: 'Yes',
|
||||
offText: 'No',
|
||||
checked: this.properties.pollBasedOnDate
|
||||
}),
|
||||
PropertyFieldCollectionData("pollQuestions", {
|
||||
key: "pollQuestions",
|
||||
label: strings.PollQuestionsLabel,
|
||||
panelHeader: strings.PollQuestionsPanelHeader,
|
||||
manageBtnLabel: strings.PollQuestionsManageButton,
|
||||
enableSorting: true,
|
||||
value: this.properties.pollQuestions,
|
||||
fields: [
|
||||
{
|
||||
id: "QTitle",
|
||||
title: strings.Q_Title_Title,
|
||||
type: CustomCollectionFieldType.custom,
|
||||
required: true,
|
||||
onCustomRender: (field, value, onUpdate, item, itemId) => {
|
||||
return (
|
||||
React.createElement("div", null,
|
||||
React.createElement("textarea",
|
||||
{
|
||||
style: { width: "220px", height: "70px" },
|
||||
placeholder: strings.Q_Title_Placeholder,
|
||||
key: itemId,
|
||||
value: value,
|
||||
onChange: (event: React.FormEvent<HTMLTextAreaElement>) => {
|
||||
onUpdate(field.id, event.currentTarget.value);
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "QOptions",
|
||||
title: strings.Q_Options_Title,
|
||||
type: CustomCollectionFieldType.custom,
|
||||
required: true,
|
||||
onCustomRender: (field, value, onUpdate, item, itemId) => {
|
||||
return (
|
||||
React.createElement("div", null,
|
||||
React.createElement("textarea",
|
||||
{
|
||||
style: { width: "220px", height: "70px" },
|
||||
placeholder: strings.Q_Options_Placeholder,
|
||||
key: itemId,
|
||||
value: value,
|
||||
onChange: (event: React.FormEvent<HTMLTextAreaElement>) => {
|
||||
onUpdate(field.id, event.currentTarget.value);
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "QMultiChoice",
|
||||
title: strings.MultiChoice_Title,
|
||||
type: CustomCollectionFieldType.boolean,
|
||||
defaultValue: false
|
||||
},
|
||||
{
|
||||
id: "QStartDate",
|
||||
title: strings.Q_StartDate_Title,
|
||||
type: CustomCollectionFieldType.custom,
|
||||
required: false,
|
||||
onCustomRender: (field, value, onUpdate, item, itemId) => {
|
||||
return (
|
||||
React.createElement(DateTimePicker, {
|
||||
key: itemId,
|
||||
showLabels: false,
|
||||
dateConvention: DateConvention.Date,
|
||||
showGoToToday: true,
|
||||
showMonthPickerAsOverlay: true,
|
||||
value: value ? new Date(value) : null,
|
||||
disabled: !this.properties.pollBasedOnDate,
|
||||
onChange: (date: Date) => {
|
||||
onUpdate(field.id, date);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
},
|
||||
{
|
||||
id: "QEndDate",
|
||||
title: strings.Q_EndDate_Title,
|
||||
type: CustomCollectionFieldType.custom,
|
||||
required: false,
|
||||
onCustomRender: (field, value, onUpdate, item, itemId) => {
|
||||
return (
|
||||
React.createElement(DateTimePicker, {
|
||||
key: itemId,
|
||||
showLabels: false,
|
||||
dateConvention: DateConvention.Date,
|
||||
showGoToToday: true,
|
||||
showMonthPickerAsOverlay: true,
|
||||
value: value ? new Date(value) : null,
|
||||
disabled: !this.properties.pollBasedOnDate,
|
||||
onChange: (date: Date) => {
|
||||
onUpdate(field.id, date);
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
],
|
||||
disabled: false
|
||||
}),
|
||||
PropertyPaneTextField('MsgAfterSubmission', {
|
||||
label: strings.MsgAfterSubmissionLabel,
|
||||
description: strings.MsgAfterSubmissionDescription,
|
||||
maxLength: 150,
|
||||
multiline: true,
|
||||
rows: 3,
|
||||
resizable: false,
|
||||
placeholder: strings.MsgAfterSubmissionPlaceholder,
|
||||
value: this.properties.MsgAfterSubmission
|
||||
}),
|
||||
PropertyPaneTextField('ResponseMsgToUser', {
|
||||
label: strings.ResponseMsgToUserLabel,
|
||||
description: strings.ResponseMsgToUserDescription,
|
||||
maxLength: 150,
|
||||
multiline: true,
|
||||
rows: 3,
|
||||
resizable: false,
|
||||
placeholder: strings.ResponseMsgToUserPlaceholder,
|
||||
value: this.properties.ResponseMsgToUser
|
||||
}),
|
||||
PropertyPaneTextField('BtnSubmitVoteText', {
|
||||
label: strings.BtnSumbitVoteLabel,
|
||||
description: strings.BtnSumbitVoteDescription,
|
||||
maxLength: 50,
|
||||
multiline: false,
|
||||
resizable: false,
|
||||
placeholder: strings.BtnSumbitVotePlaceholder,
|
||||
value: this.properties.BtnSubmitVoteText
|
||||
}),
|
||||
PropertyPaneTextField('NoPollMsg', {
|
||||
label: strings.NoPollMsgLabel,
|
||||
description: strings.NoPollMsgDescription,
|
||||
maxLength: 150,
|
||||
multiline: true,
|
||||
rows: 3,
|
||||
resizable: false,
|
||||
placeholder: strings.NoPollMsgPlaceholder,
|
||||
value: this.properties.NoPollMsg
|
||||
}),
|
||||
PropertyFieldChoiceGroupWithCallout('chartType', {
|
||||
calloutContent: React.createElement('div', {}, strings.ChartFieldCalloutText),
|
||||
calloutTrigger: CalloutTriggers.Hover,
|
||||
key: 'choice_charttype',
|
||||
label: strings.ChartFieldLabel,
|
||||
options: [
|
||||
{
|
||||
key: 'pie',
|
||||
text: 'Pie',
|
||||
checked: this.properties.chartType === ChartType.Pie,
|
||||
iconProps: { officeFabricIconFontName: 'PieSingle' }
|
||||
}, {
|
||||
key: 'doughnut',
|
||||
text: 'Doughnut',
|
||||
checked: this.properties.chartType === ChartType.Doughnut,
|
||||
iconProps: { officeFabricIconFontName: 'DonutChart' }
|
||||
}, {
|
||||
key: 'bar',
|
||||
text: 'Bar',
|
||||
checked: this.properties.chartType === ChartType.Bar,
|
||||
iconProps: { officeFabricIconFontName: 'BarChartVertical' }
|
||||
}, {
|
||||
key: 'horizontalBar',
|
||||
text: 'Horizontal Bar',
|
||||
checked: this.properties.chartType === ChartType.HorizontalBar,
|
||||
iconProps: { officeFabricIconFontName: 'BarChartHorizontal' }
|
||||
}, {
|
||||
key: 'line',
|
||||
text: 'Line',
|
||||
checked: this.properties.chartType === ChartType.Line,
|
||||
iconProps: { officeFabricIconFontName: 'LineChart' }
|
||||
}]
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,96 +6,101 @@ import { IOptionsContainerProps } from './IOptionsContainerProps';
|
|||
import * as _ from 'lodash';
|
||||
|
||||
export interface IOptionsContainerState {
|
||||
selChoices?: string[];
|
||||
selChoices?: string[];
|
||||
}
|
||||
|
||||
export default class OptionsContainer extends React.Component<IOptionsContainerProps, IOptionsContainerState> {
|
||||
constructor(props: IOptionsContainerProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
selChoices: []
|
||||
};
|
||||
}
|
||||
constructor(props: IOptionsContainerProps) {
|
||||
super(props);
|
||||
this.state = {
|
||||
selChoices: []
|
||||
};
|
||||
}
|
||||
|
||||
public render(): JSX.Element {
|
||||
const { disabled, selectedKey, label, options, onChange, multiSelect } = this.props;
|
||||
return (
|
||||
<div>
|
||||
{multiSelect ? (
|
||||
<div style={{ paddingTop: "15px" }}>
|
||||
<List items={this.getOptions()} onRenderCell={this._onRenderCell} />
|
||||
</div>
|
||||
) : (
|
||||
<ChoiceGroup disabled={disabled}
|
||||
selectedKey={this._getSelectedKey()}
|
||||
options={this.onRenderChoiceOptions()} required={true} label=""
|
||||
onChange={this._onChange}
|
||||
/>
|
||||
)
|
||||
public render(): JSX.Element {
|
||||
const { disabled, selectedKey, label, options, onChange, multiSelect } = this.props;
|
||||
return (
|
||||
<div>
|
||||
{multiSelect ? (
|
||||
<div style={{ paddingTop: "15px" }}>
|
||||
<List items={this.getOptions()} onRenderCell={this._onRenderCell} />
|
||||
</div>
|
||||
) : (
|
||||
<ChoiceGroup disabled={disabled}
|
||||
selectedKey={this._getSelectedKey()}
|
||||
options={this.onRenderChoiceOptions()} required={true} label=""
|
||||
onChange={this._onChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private getOptions = (): string[] => {
|
||||
let tempChoices: string[] = [];
|
||||
if (this.props.options.indexOf(',') >= 0) {
|
||||
let tmpChoices = this.props.options.split(',');
|
||||
tmpChoices.map(choice => {
|
||||
if (choice && choice.trim().length > 0) tempChoices.push(choice);
|
||||
});
|
||||
} else tempChoices.push(this.props.options);
|
||||
return tempChoices;
|
||||
}
|
||||
|
||||
private _onRenderCell = (item: any, index: number | undefined): JSX.Element => {
|
||||
if (item && item.length > 0) {
|
||||
return (
|
||||
<div style={{ marginBottom: "15px" }}>
|
||||
<Checkbox label={item} onChange={this._makeChangeHandler(item)} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private getOptions = (): string[] => {
|
||||
let tempChoices: string[] = [];
|
||||
if (this.props.options.indexOf(',') >= 0) {
|
||||
tempChoices = this.props.options.split(',');
|
||||
} else tempChoices.push(this.props.options);
|
||||
return tempChoices;
|
||||
}
|
||||
|
||||
private _onRenderCell = (item: any, index: number | undefined): JSX.Element => {
|
||||
return (
|
||||
<div style={{ marginBottom: "15px" }}>
|
||||
<Checkbox label={item} onChange={this._makeChangeHandler(item)} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
private onRenderChoiceOptions(): IChoiceGroupOption[] {
|
||||
let choices: IChoiceGroupOption[] = [];
|
||||
let tempChoices: string[] = this.getOptions();
|
||||
if (tempChoices.length > 0) {
|
||||
tempChoices.map((choice: string) => {
|
||||
choices.push({
|
||||
key: choice.trim(),
|
||||
text: choice.trim()
|
||||
});
|
||||
});
|
||||
} else {
|
||||
choices.push({
|
||||
key: '0',
|
||||
text: "Sorry, no choices found",
|
||||
disabled: true,
|
||||
});
|
||||
}
|
||||
return choices;
|
||||
}
|
||||
|
||||
private _getSelectedKey = (): string => {
|
||||
return this.props.selectedKey();
|
||||
}
|
||||
|
||||
private _onChange = (ev: React.FormEvent<HTMLInputElement>, option: any): void => {
|
||||
this.props.onChange(ev, option, false);
|
||||
}
|
||||
|
||||
private _makeChangeHandler = (item: string) => {
|
||||
return (ev: any, checked: boolean) => this._onCheckboxChange(ev, checked, item);
|
||||
}
|
||||
|
||||
private _onCheckboxChange = (ev: any, isChecked: boolean, item: string) => {
|
||||
let finalSel: string[] = this.state.selChoices;
|
||||
if (finalSel.length > 0) {
|
||||
if (isChecked) {
|
||||
finalSel.push(item);
|
||||
} else finalSel = _.filter(finalSel, (o) => { return o !== item; });
|
||||
} else {
|
||||
if (isChecked) finalSel.push(item);
|
||||
private onRenderChoiceOptions(): IChoiceGroupOption[] {
|
||||
let choices: IChoiceGroupOption[] = [];
|
||||
let tempChoices: string[] = this.getOptions();
|
||||
if (tempChoices.length > 0) {
|
||||
tempChoices.map((choice: string) => {
|
||||
choices.push({
|
||||
key: choice.trim(),
|
||||
text: choice.trim()
|
||||
});
|
||||
});
|
||||
} else {
|
||||
choices.push({
|
||||
key: '0',
|
||||
text: "Sorry, no choices found",
|
||||
disabled: true,
|
||||
});
|
||||
}
|
||||
return choices;
|
||||
}
|
||||
|
||||
private _getSelectedKey = (): string => {
|
||||
return this.props.selectedKey();
|
||||
}
|
||||
|
||||
private _onChange = (ev: React.FormEvent<HTMLInputElement>, option: any): void => {
|
||||
this.props.onChange(ev, option, false);
|
||||
}
|
||||
|
||||
private _makeChangeHandler = (item: string) => {
|
||||
return (ev: any, checked: boolean) => this._onCheckboxChange(ev, checked, item);
|
||||
}
|
||||
|
||||
private _onCheckboxChange = (ev: any, isChecked: boolean, item: string) => {
|
||||
let finalSel: string[] = this.state.selChoices;
|
||||
if (finalSel.length > 0) {
|
||||
if (isChecked) {
|
||||
finalSel.push(item);
|
||||
} else finalSel = _.filter(finalSel, (o) => { return o !== item; });
|
||||
} else {
|
||||
if (isChecked) finalSel.push(item);
|
||||
}
|
||||
this.setState({ selChoices: finalSel });
|
||||
this.props.onChange(ev, { key: finalSel }, true);
|
||||
}
|
||||
this.setState({ selChoices: finalSel });
|
||||
this.props.onChange(ev, { key: finalSel }, true);
|
||||
}
|
||||
|
||||
}
|
|
@ -29,7 +29,8 @@
|
|||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
|
|
|
@ -0,0 +1,344 @@
|
|||
# Upgrade project react-simple-poll to v1.11.0
|
||||
|
||||
Date: 10/16/2020
|
||||
|
||||
## Findings
|
||||
|
||||
Following is the list of steps required to upgrade your project to SharePoint Framework version 1.11.0. [Summary](#Summary) of the modifications is included at the end of the report.
|
||||
|
||||
### FN001001 @microsoft/sp-core-library | Required
|
||||
|
||||
Upgrade SharePoint Framework dependency package @microsoft/sp-core-library
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -SE @microsoft/sp-core-library@1.11.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001002 @microsoft/sp-lodash-subset | Required
|
||||
|
||||
Upgrade SharePoint Framework dependency package @microsoft/sp-lodash-subset
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -SE @microsoft/sp-lodash-subset@1.11.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001003 @microsoft/sp-office-ui-fabric-core | Required
|
||||
|
||||
Upgrade SharePoint Framework dependency package @microsoft/sp-office-ui-fabric-core
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -SE @microsoft/sp-office-ui-fabric-core@1.11.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001004 @microsoft/sp-webpart-base | Required
|
||||
|
||||
Upgrade SharePoint Framework dependency package @microsoft/sp-webpart-base
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -SE @microsoft/sp-webpart-base@1.11.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001005 @types/react | Required
|
||||
|
||||
Remove SharePoint Framework dependency package @types/react
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm un -S @types/react
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001006 @types/react-dom | Required
|
||||
|
||||
Remove SharePoint Framework dependency package @types/react-dom
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm un -S @types/react-dom
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001007 @types/webpack-env | Required
|
||||
|
||||
Remove SharePoint Framework dependency package @types/webpack-env
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm un -S @types/webpack-env
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001010 @types/es6-promise | Required
|
||||
|
||||
Remove SharePoint Framework dependency package @types/es6-promise
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm un -S @types/es6-promise
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001021 @microsoft/sp-property-pane | Required
|
||||
|
||||
Upgrade SharePoint Framework dependency package @microsoft/sp-property-pane
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -SE @microsoft/sp-property-pane@1.11.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001022 office-ui-fabric-react | Required
|
||||
|
||||
Upgrade SharePoint Framework dependency package office-ui-fabric-react
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -SE office-ui-fabric-react@6.214.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN002001 @microsoft/sp-build-web | Required
|
||||
|
||||
Upgrade SharePoint Framework dev dependency package @microsoft/sp-build-web
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -DE @microsoft/sp-build-web@1.11.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN002002 @microsoft/sp-module-interfaces | Required
|
||||
|
||||
Upgrade SharePoint Framework dev dependency package @microsoft/sp-module-interfaces
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -DE @microsoft/sp-module-interfaces@1.11.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN002003 @microsoft/sp-webpart-workbench | Required
|
||||
|
||||
Upgrade SharePoint Framework dev dependency package @microsoft/sp-webpart-workbench
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -DE @microsoft/sp-webpart-workbench@1.11.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN002009 @microsoft/sp-tslint-rules | Required
|
||||
|
||||
Upgrade SharePoint Framework dev dependency package @microsoft/sp-tslint-rules
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -DE @microsoft/sp-tslint-rules@1.11.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN002013 @types/webpack-env | Required
|
||||
|
||||
Install SharePoint Framework dev dependency package @types/webpack-env
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -DE @types/webpack-env@1.13.1
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN002014 @types/es6-promise | Required
|
||||
|
||||
Install SharePoint Framework dev dependency package @types/es6-promise
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -DE @types/es6-promise@0.0.33
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN002015 @types/react | Required
|
||||
|
||||
Install SharePoint Framework dev dependency package @types/react
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -DE @types/react@16.8.8
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN002016 @types/react-dom | Required
|
||||
|
||||
Install SharePoint Framework dev dependency package @types/react-dom
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -DE @types/react-dom@16.8.3
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN006004 package-solution.json developer | Optional
|
||||
|
||||
In package-solution.json add developer section
|
||||
|
||||
In file [./config/package-solution.json](./config/package-solution.json) update the code as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"solution": {
|
||||
"developer": {
|
||||
"name": "Contoso",
|
||||
"privacyUrl": "https://contoso.com/privacy",
|
||||
"termsOfUseUrl": "https://contoso.com/terms-of-use",
|
||||
"websiteUrl": "https://contoso.com/my-app",
|
||||
"mpnId": "000000"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
File: [./config/package-solution.json](./config/package-solution.json)
|
||||
|
||||
### FN010001 .yo-rc.json version | Recommended
|
||||
|
||||
Update version in .yo-rc.json
|
||||
|
||||
In file [./.yo-rc.json](./.yo-rc.json) update the code as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"version": "1.11.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
File: [./.yo-rc.json](./.yo-rc.json)
|
||||
|
||||
### FN012012 tsconfig.json include property | Required
|
||||
|
||||
Update tsconfig.json include property
|
||||
|
||||
In file [./tsconfig.json](./tsconfig.json) update the code as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"include": [
|
||||
"src/**/*.tsx"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
File: [./tsconfig.json](./tsconfig.json)
|
||||
|
||||
### FN017001 Run npm dedupe | Optional
|
||||
|
||||
If, after upgrading npm packages, when building the project you have errors similar to: "error TS2345: Argument of type 'SPHttpClientConfiguration' is not assignable to parameter of type 'SPHttpClientConfiguration'", try running 'npm dedupe' to cleanup npm packages.
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm dedupe
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
## Summary
|
||||
|
||||
### Execute script
|
||||
|
||||
```sh
|
||||
npm i -SE @microsoft/sp-core-library@1.11.0 @microsoft/sp-lodash-subset@1.11.0 @microsoft/sp-office-ui-fabric-core@1.11.0 @microsoft/sp-webpart-base@1.11.0 @microsoft/sp-property-pane@1.11.0 office-ui-fabric-react@6.214.0
|
||||
npm i -DE @microsoft/sp-build-web@1.11.0 @microsoft/sp-module-interfaces@1.11.0 @microsoft/sp-webpart-workbench@1.11.0 @microsoft/sp-tslint-rules@1.11.0 @types/webpack-env@1.13.1 @types/es6-promise@0.0.33 @types/react@16.8.8 @types/react-dom@16.8.3
|
||||
npm un -S @types/react @types/react-dom @types/webpack-env @types/es6-promise
|
||||
npm dedupe
|
||||
```
|
||||
|
||||
### Modify files
|
||||
|
||||
#### [./config/package-solution.json](./config/package-solution.json)
|
||||
|
||||
In package-solution.json add developer section:
|
||||
|
||||
```json
|
||||
{
|
||||
"solution": {
|
||||
"developer": {
|
||||
"name": "Contoso",
|
||||
"privacyUrl": "https://contoso.com/privacy",
|
||||
"termsOfUseUrl": "https://contoso.com/terms-of-use",
|
||||
"websiteUrl": "https://contoso.com/my-app",
|
||||
"mpnId": "000000"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### [./.yo-rc.json](./.yo-rc.json)
|
||||
|
||||
Update version in .yo-rc.json:
|
||||
|
||||
```json
|
||||
{
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"version": "1.11.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### [./tsconfig.json](./tsconfig.json)
|
||||
|
||||
Update tsconfig.json include property:
|
||||
|
||||
```json
|
||||
{
|
||||
"include": [
|
||||
"src/**/*.tsx"
|
||||
]
|
||||
}
|
||||
```
|
|
@ -0,0 +1,25 @@
|
|||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
|
||||
[*]
|
||||
|
||||
# change these settings to your own preference
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
# we recommend you to keep these unchanged
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[{package,bower}.json]
|
||||
indent_style = space
|
||||
indent_size = 2
|
|
@ -0,0 +1,32 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
|
||||
# Build generated files
|
||||
dist
|
||||
lib
|
||||
solution
|
||||
temp
|
||||
*.sppkg
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# OSX
|
||||
.DS_Store
|
||||
|
||||
# Visual Studio files
|
||||
.ntvs_analysis.dat
|
||||
.vs
|
||||
bin
|
||||
obj
|
||||
|
||||
# Resx Generated Code
|
||||
*.resx.ts
|
||||
|
||||
# Styles Generated Code
|
||||
*.scss.ts
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"version": "1.11.0",
|
||||
"libraryName": "react-tailwindcss",
|
||||
"libraryId": "62daa1f6-c9b4-4664-b101-37ccbddb47da",
|
||||
"environment": "spo",
|
||||
"packageManager": "npm",
|
||||
"isCreatingSolution": true,
|
||||
"isDomainIsolated": false,
|
||||
"componentType": "webpart"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
---
|
||||
page_type: sample
|
||||
products:
|
||||
- office-sp
|
||||
languages:
|
||||
- javascript
|
||||
- typescript
|
||||
extensions:
|
||||
contentType: samples
|
||||
technologies:
|
||||
- SharePoint Framework
|
||||
- TailWind CSS
|
||||
platforms:
|
||||
- React
|
||||
createdDate: 10/17/2020 12:00:00 AM
|
||||
---
|
||||
|
||||
# react-tailwindcss
|
||||
|
||||
## Summary
|
||||
|
||||
This project shows how to integrate [Tailwind CSS](https://tailwindcss.com/) framework into a SPFx React project by:
|
||||
- Create a custom Tailwind CSS config file
|
||||
- Create a custom Gulp Task to process the Tailwind CSS generated file and optimize it
|
||||
- Using CSS custom properties to manage in Tailwind CSS Classes the Theme Variant into sections
|
||||
- Avoid writing SASS but only use Tailwind CSS classes to style components
|
||||
|
||||
![WebPart](./assets/react-tailwindcss-overview.gif)
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
|
||||
![SPFx 1.11](https://img.shields.io/badge/version-1.11-green.svg)
|
||||
|
||||
## Applies to
|
||||
|
||||
- [SharePoint Framework](https://aka.ms/spfx)
|
||||
- [Microsoft 365 tenant](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant)
|
||||
|
||||
> Get your own free development tenant by subscribing to [Microsoft 365 developer program](http://aka.ms/o365devprogram)
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Basic knowledge of [Tailwind CSS](https://tailwindcss.com/)
|
||||
- Basic knowledge of [GulpJs](https://gulpjs.com/)
|
||||
|
||||
## Solution
|
||||
|
||||
Solution|Author(s)
|
||||
--------|---------
|
||||
react-tailwindcss | Fabio Franzini, [@franzinifabio](https://twitter.com/franzinifabio)
|
||||
|
||||
## Version history
|
||||
|
||||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0|October 17, 2020|Initial release
|
||||
|
||||
## 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.**
|
||||
|
||||
---
|
||||
|
||||
## Minimal Path to Awesome
|
||||
|
||||
- Clone this repository
|
||||
- Ensure that you are at the solution folder
|
||||
- in the command-line run:
|
||||
- **npm install**
|
||||
- **gulp serve**
|
||||
|
||||
## References
|
||||
|
||||
- [Getting started with Tailwind CSS](https://tailwindcss.com/)
|
||||
- [Getting started with SharePoint Framework](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/set-up-your-developer-tenant)
|
||||
- [Building for Microsoft teams](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/build-for-teams-overview)
|
||||
- [Use Microsoft Graph in your solution](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/web-parts/get-started/using-microsoft-graph-apis)
|
||||
- [Publish SharePoint Framework applications to the Marketplace](https://docs.microsoft.com/en-us/sharepoint/dev/spfx/publish-to-marketplace-overview)
|
||||
- [Microsoft 365 Patterns and Practices](https://aka.ms/m365pnp) - Guidance, tooling, samples and open-source controls for your Microsoft 365 development
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-tailwindcss" />
|
After Width: | Height: | Size: 13 MiB |
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/config.2.0.schema.json",
|
||||
"version": "2.0",
|
||||
"bundles": {
|
||||
"hello-tailwind-web-part": {
|
||||
"components": [
|
||||
{
|
||||
"entrypoint": "./lib/webparts/HelloTailwindCss/HelloTailwindCssWebPart.js",
|
||||
"manifest": "./src/webparts/HelloTailwindCss/HelloTailwindCssWebPart.manifest.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"externals": {},
|
||||
"localizedResources": {
|
||||
"HelloTailwindCssWebPartStrings": "lib/webparts/HelloTailwindCss/loc/{locale}.js"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/copy-assets.schema.json",
|
||||
"deployCdnPath": "temp/deploy"
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/deploy-azure-storage.schema.json",
|
||||
"workingDir": "./temp/deploy/",
|
||||
"account": "<!-- STORAGE ACCOUNT NAME -->",
|
||||
"container": "react-tailwindcss",
|
||||
"accessKey": "<!-- ACCESS KEY -->"
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/package-solution.schema.json",
|
||||
"solution": {
|
||||
"name": "react-tailwindcss-client-side-solution",
|
||||
"id": "62daa1f6-c9b4-4664-b101-37ccbddb47da",
|
||||
"version": "1.0.0.0",
|
||||
"includeClientSideAssets": true,
|
||||
"isDomainIsolated": false,
|
||||
"developer": {
|
||||
"name": "",
|
||||
"websiteUrl": "",
|
||||
"privacyUrl": "",
|
||||
"termsOfUseUrl": "",
|
||||
"mpnId": ""
|
||||
}
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/react-tailwindcss.sppkg"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/core-build/serve.schema.json",
|
||||
"port": 4321,
|
||||
"https": true,
|
||||
"initialPage": "https://localhost:5432/workbench",
|
||||
"api": {
|
||||
"port": 5432,
|
||||
"entryPath": "node_modules/@microsoft/sp-webpart-workbench/lib/api/"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/write-manifests.schema.json",
|
||||
"cdnBasePath": "<!-- PATH TO CDN -->"
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
'use strict';
|
||||
|
||||
const build = require('@microsoft/sp-build-web');
|
||||
|
||||
build.addSuppression(`Warning - [sass] The local CSS class 'ms-Grid' is not camelCase and will not be type-safe.`);
|
||||
|
||||
// Step 1 + './src/tailwind.css' + './tailwind.config.js'
|
||||
let tailwindBuild = build.subTask('build-tailwind', (gulp, buildOptions, done) => {
|
||||
const postcss = require('gulp-postcss');
|
||||
|
||||
gulp.src(`${buildOptions.srcFolder}/tailwind.css`)
|
||||
.pipe(postcss([
|
||||
require('tailwindcss')('./tailwind.config.js'),
|
||||
require('gulp-autoprefixer')
|
||||
]))
|
||||
.pipe(gulp.dest(buildOptions.libFolder));
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
build.rig.addPostBuildTask(tailwindBuild);
|
||||
// End Step 1
|
||||
|
||||
build.initialize(require('gulp'));
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"name": "react-tailwindcss",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"main": "lib/index.js",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npm run tailwind:css && gulp bundle",
|
||||
"clean": "gulp clean",
|
||||
"test": "gulp test",
|
||||
"build:tailwind": "postcss tailwind.source.css -o src/tailwind.css"
|
||||
},
|
||||
"dependencies": {
|
||||
"@microsoft/sp-core-library": "1.11.0",
|
||||
"@microsoft/sp-lodash-subset": "1.11.0",
|
||||
"@microsoft/sp-office-ui-fabric-core": "^1.11.0",
|
||||
"@microsoft/sp-property-pane": "1.11.0",
|
||||
"@microsoft/sp-webpart-base": "1.11.0",
|
||||
"office-ui-fabric-react": "6.214.0",
|
||||
"react": "16.8.5",
|
||||
"react-dom": "16.8.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/rush-stack-compiler-3.3": "0.3.5",
|
||||
"@microsoft/sp-build-web": "1.11.0",
|
||||
"@microsoft/sp-module-interfaces": "1.11.0",
|
||||
"@microsoft/sp-tslint-rules": "1.11.0",
|
||||
"@microsoft/sp-webpart-workbench": "1.11.0",
|
||||
"@types/chai": "3.4.34",
|
||||
"@types/es6-promise": "0.0.33",
|
||||
"@types/mocha": "2.2.38",
|
||||
"@types/react": "16.8.8",
|
||||
"@types/react-dom": "16.8.3",
|
||||
"@types/webpack-env": "1.13.1",
|
||||
"ajv": "~5.2.2",
|
||||
"gulp": "~3.9.1",
|
||||
"gulp-autoprefixer": "^7.0.1",
|
||||
"gulp-postcss": "^8.0.0",
|
||||
"gulp-sass": "^4.1.0",
|
||||
"tailwindcss": "^1.8.10"
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
// A file is required to be in the root of the /src directory by the TypeScript compiler
|
|
@ -0,0 +1,136 @@
|
|||
@import "tailwindcss/components";
|
||||
@import "tailwindcss/utilities";
|
||||
|
||||
:root {
|
||||
--tw-fui-themeDarker: #004578;
|
||||
--tw-fui-themeDark: #005a9e;
|
||||
--tw-fui-themeDarkAlt: #106ebe;
|
||||
--tw-fui-themePrimary: #0078d4;
|
||||
--tw-fui-themeSecondary: #2b88d8;
|
||||
--tw-fui-themeTertiary: #71afe5;
|
||||
--tw-fui-themeLight: #c7e0f4;
|
||||
--tw-fui-themeLighter: #deecf9;
|
||||
--tw-fui-themeLighterAlt: #eff6fc;
|
||||
--tw-fui-black: #000000;
|
||||
--tw-fui-blackTranslucent40: rgba(0, 0, 0, .4);
|
||||
--tw-fui-neutralDark: #212121;
|
||||
--tw-fui-neutralPrimary: #333333;
|
||||
--tw-fui-neutralPrimaryAlt: #3c3c3c;
|
||||
--tw-fui-neutralSecondary: #666666;
|
||||
--tw-fui-neutralSecondaryAlt: #767676;
|
||||
--tw-fui-neutralTertiary: #a6a6a6;
|
||||
--tw-fui-neutralTertiaryAlt: #c8c8c8;
|
||||
--tw-fui-neutralQuaternary: #d0d0d0;
|
||||
--tw-fui-neutralQuaternaryAlt: #dadada;
|
||||
--tw-fui-neutralLight: #eaeaea;
|
||||
--tw-fui-neutralLighter: #f4f4f4;
|
||||
--tw-fui-neutralLighterAlt: #f8f8f8;
|
||||
--tw-fui-accent: #0078d4;
|
||||
--tw-fui-white: #ffffff;
|
||||
--tw-fui-whiteTranslucent40: rgba(255, 255, 255, .4);
|
||||
--tw-fui-yellow: #ffb900;
|
||||
--tw-fui-yellowLight: #fff100;
|
||||
--tw-fui-orange: #d83b01;
|
||||
--tw-fui-orangeLight: #ea4300;
|
||||
--tw-fui-orangeLighter: #ff8c00;
|
||||
--tw-fui-redDark: #a80000;
|
||||
--tw-fui-red: #e81123;
|
||||
--tw-fui-magentaDark: #5c005c;
|
||||
--tw-fui-magenta: #b4009e;
|
||||
--tw-fui-magentaLight: #e3008c;
|
||||
--tw-fui-purpleDark: #32145a;
|
||||
--tw-fui-purple: #5c2d91;
|
||||
--tw-fui-purpleLight: #b4a0ff;
|
||||
--tw-fui-blueDark: #002050;
|
||||
--tw-fui-blueMid: #00188f;
|
||||
--tw-fui-blue: #0078d4;
|
||||
--tw-fui-blueLight: #00bcf2;
|
||||
--tw-fui-tealDark: #004b50;
|
||||
--tw-fui-teal: #008272;
|
||||
--tw-fui-tealLight: #00b294;
|
||||
--tw-fui-greenDark: #004b1c;
|
||||
--tw-fui-green: #107c10;
|
||||
--tw-fui-greenLight: #bad80a;
|
||||
/* ***** */
|
||||
--tw-fui-bodyBackground: #ffffff;
|
||||
--tw-fui-bodyStandoutBackground: #f8f8f8;
|
||||
--tw-fui-bodyFrameBackground: #ffffff;
|
||||
--tw-fui-bodyFrameDivider: #eaeaea;
|
||||
--tw-fui-bodyText: #333333;
|
||||
--tw-fui-bodyTextChecked: #000000;
|
||||
--tw-fui-bodySubtext: #666666;
|
||||
--tw-fui-bodyDivider: #eaeaea;
|
||||
--tw-fui-disabledBackground: #f4f4f4;
|
||||
--tw-fui-disabledText: #a6a6a6;
|
||||
--tw-fui-disabledSubtext: #d0d0d0;
|
||||
--tw-fui-disabledBodyText: #a6a6a6;
|
||||
--tw-fui-disabledBodySubtext: #c8c8c8;
|
||||
--tw-fui-focusBorder: #666666;
|
||||
--tw-fui-variantBorder: #eaeaea;
|
||||
--tw-fui-variantBorderHovered: #a6a6a6;
|
||||
--tw-fui-defaultStateBackground: #f8f8f8;
|
||||
--tw-fui-errorText: #a80000;
|
||||
--tw-fui-warningText: #333333;
|
||||
--tw-fui-errorBackground: rgba(232, 17, 35, .2);
|
||||
--tw-fui-blockingBackground: rgba(234, 67, 0, .2);
|
||||
--tw-fui-warningBackground: rgba(255, 185, 0, .2);
|
||||
--tw-fui-warningHighlight: #ffb900;
|
||||
--tw-fui-successBackground: rgba(186, 216, 10, .2);
|
||||
--tw-fui-inputBorder: #a6a6a6;
|
||||
--tw-fui-inputBorderHovered: #333333;
|
||||
--tw-fui-inputBackground: #ffffff;
|
||||
--tw-fui-inputBackgroundChecked: #0078d4;
|
||||
--tw-fui-inputBackgroundCheckedHovered: #106ebe;
|
||||
--tw-fui-inputForegroundChecked: #ffffff;
|
||||
--tw-fui-inputFocusBorderAlt: #0078d4;
|
||||
--tw-fui-smallInputBorder: #666666;
|
||||
--tw-fui-inputText: #333333;
|
||||
--tw-fui-inputTextHovered: #212121;
|
||||
--tw-fui-inputPlaceholderText: #666666;
|
||||
--tw-fui-buttonBackground: #f4f4f4;
|
||||
--tw-fui-buttonBackgroundChecked: #c8c8c8;
|
||||
--tw-fui-buttonBackgroundHovered: #eaeaea;
|
||||
--tw-fui-buttonBackgroundCheckedHovered: #eaeaea;
|
||||
--tw-fui-buttonBackgroundPressed: #eaeaea;
|
||||
--tw-fui-buttonBackgroundDisabled: #f4f4f4;
|
||||
--tw-fui-buttonBorder: transparent;
|
||||
--tw-fui-buttonText: #333333;
|
||||
--tw-fui-buttonTextHovered: #212121;
|
||||
--tw-fui-buttonTextChecked: #212121;
|
||||
--tw-fui-buttonTextCheckedHovered: #000000;
|
||||
--tw-fui-buttonTextPressed: #212121;
|
||||
--tw-fui-buttonTextDisabled: #a6a6a6;
|
||||
--tw-fui-buttonBorderDisabled: transparent;
|
||||
--tw-fui-primaryButtonBackground: #0078d4;
|
||||
--tw-fui-primaryButtonBackgroundHovered: #106ebe;
|
||||
--tw-fui-primaryButtonBackgroundPressed: #005a9e;
|
||||
--tw-fui-primaryButtonBackgroundDisabled: #f4f4f4;
|
||||
--tw-fui-primaryButtonBorder: transparent;
|
||||
--tw-fui-primaryButtonText: #ffffff;
|
||||
--tw-fui-primaryButtonTextHovered: #ffffff;
|
||||
--tw-fui-primaryButtonTextPressed: #ffffff;
|
||||
--tw-fui-primaryButtonTextDisabled: #d0d0d0;
|
||||
--tw-fui-accentButtonBackground: #0078d4;
|
||||
--tw-fui-accentButtonText: #ffffff;
|
||||
--tw-fui-menuBackground: #ffffff;
|
||||
--tw-fui-menuDivider: #c8c8c8;
|
||||
--tw-fui-menuIcon: #0078d4;
|
||||
--tw-fui-menuHeader: #0078d4;
|
||||
--tw-fui-menuItemBackgroundHovered: #f4f4f4;
|
||||
--tw-fui-menuItemBackgroundPressed: #eaeaea;
|
||||
--tw-fui-menuItemText: #333333;
|
||||
--tw-fui-menuItemTextHovered: #212121;
|
||||
--tw-fui-listBackground: #ffffff;
|
||||
--tw-fui-listText: #333333;
|
||||
--tw-fui-listItemBackgroundHovered: #f4f4f4;
|
||||
--tw-fui-listItemBackgroundChecked: #eaeaea;
|
||||
--tw-fui-listItemBackgroundCheckedHovered: #dadada;
|
||||
--tw-fui-listHeaderBackgroundHovered: #f4f4f4;
|
||||
--tw-fui-listHeaderBackgroundPressed: #eaeaea;
|
||||
--tw-fui-actionLink: #333333;
|
||||
--tw-fui-actionLinkHovered: #212121;
|
||||
--tw-fui-link: #0078d4;
|
||||
--tw-fui-linkHovered: #004578;
|
||||
--tw-fui-listTextColor: #333333;
|
||||
--tw-fui-menuItemBackgroundChecked: #eaeaea;
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
|
||||
"id": "acebbfec-5fc8-42b0-94e5-cfbc43222cae",
|
||||
"alias": "HelloTailwindCssWebPart",
|
||||
"componentType": "WebPart",
|
||||
"supportsThemeVariants": true,
|
||||
// The "*" signifies that the version should be taken from the package.json
|
||||
"version": "*",
|
||||
"manifestVersion": 2,
|
||||
|
||||
// If true, the component can only be installed on sites where Custom Script is allowed.
|
||||
// Components that allow authors to embed arbitrary script code should set this to true.
|
||||
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
|
||||
"requiresCustomScript": false,
|
||||
"supportedHosts": ["SharePointWebPart"],
|
||||
|
||||
"preconfiguredEntries": [{
|
||||
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
|
||||
"group": { "default": "Other" },
|
||||
"title": { "default": "Hello TailwindCss" },
|
||||
"description": { "default": "Hello TailwindCss description" },
|
||||
"officeFabricIconFontName": "Duststorm",
|
||||
"properties": {
|
||||
"description": "Hello TailwindCss"
|
||||
}
|
||||
}]
|
||||
}
|
|
@ -0,0 +1,223 @@
|
|||
import * as React from 'react';
|
||||
import * as ReactDom from 'react-dom';
|
||||
import { Version } from '@microsoft/sp-core-library';
|
||||
import {
|
||||
IPropertyPaneConfiguration,
|
||||
PropertyPaneTextField
|
||||
} from '@microsoft/sp-property-pane';
|
||||
import { BaseClientSideWebPart } from '@microsoft/sp-webpart-base';
|
||||
import * as strings from 'HelloTailwindCssWebPartStrings';
|
||||
import HelloTailwindCss from './components/HelloTailwindCss';
|
||||
import { IHelloTailwindCssProps } from './components/IHelloTailwindCssProps';
|
||||
import { ThemeProvider, ThemeChangedEventArgs, IReadonlyTheme } from '@microsoft/sp-component-base';
|
||||
|
||||
|
||||
export interface IHelloTailwindCssWebPartProps {
|
||||
description: string;
|
||||
}
|
||||
|
||||
export default class HelloTailwindCssWebPart extends BaseClientSideWebPart<IHelloTailwindCssWebPartProps> {
|
||||
|
||||
private _themeProvider: ThemeProvider;
|
||||
private _themeVariant: IReadonlyTheme | undefined;
|
||||
|
||||
protected onInit(): Promise<void> {
|
||||
// Consume the new ThemeProvider service
|
||||
this._themeProvider = this.context.serviceScope.consume(ThemeProvider.serviceKey);
|
||||
|
||||
// If it exists, get the theme variant
|
||||
this._themeVariant = this._themeProvider.tryGetTheme();
|
||||
|
||||
// Register a handler to be notified if the theme variant changes
|
||||
this._themeProvider.themeChangedEvent.add(this, this._handleThemeChangedEvent);
|
||||
|
||||
// Apply theme variant as CSS Variables at current DOM node
|
||||
this._applyThemeVariant();
|
||||
|
||||
return super.onInit();
|
||||
}
|
||||
|
||||
private _handleThemeChangedEvent(args: ThemeChangedEventArgs): void {
|
||||
this._themeVariant = args.theme;
|
||||
this._applyThemeVariant();
|
||||
this.render();
|
||||
}
|
||||
|
||||
private _applyThemeVariant() {
|
||||
let style = this.domElement.style;
|
||||
|
||||
style.setProperty('--tw-fui-themeDarker', this._themeVariant.palette.themeDarker);
|
||||
style.setProperty('--tw-fui-themeDark', this._themeVariant.palette.themeDark);
|
||||
style.setProperty('--tw-fui-themeDarkAlt', this._themeVariant.palette.themeDarkAlt);
|
||||
style.setProperty('--tw-fui-themePrimary', this._themeVariant.palette.themePrimary);
|
||||
style.setProperty('--tw-fui-themeSecondary', this._themeVariant.palette.themeSecondary);
|
||||
style.setProperty('--tw-fui-themeTertiary', this._themeVariant.palette.themeTertiary);
|
||||
style.setProperty('--tw-fui-themeLight', this._themeVariant.palette.themeLight);
|
||||
style.setProperty('--tw-fui-themeLighter', this._themeVariant.palette.themeLighter);
|
||||
style.setProperty('--tw-fui-themeLighterAlt', this._themeVariant.palette.themeLighterAlt);
|
||||
style.setProperty('--tw-fui-black', this._themeVariant.palette.black);
|
||||
style.setProperty('--tw-fui-blackTranslucent40', this._themeVariant.palette.blackTranslucent40);
|
||||
style.setProperty('--tw-fui-neutralDark', this._themeVariant.palette.neutralDark);
|
||||
style.setProperty('--tw-fui-neutralPrimary', this._themeVariant.palette.neutralPrimary);
|
||||
style.setProperty('--tw-fui-neutralPrimaryAlt', this._themeVariant.palette.neutralPrimaryAlt);
|
||||
style.setProperty('--tw-fui-neutralSecondary', this._themeVariant.palette.neutralSecondary);
|
||||
style.setProperty('--tw-fui-neutralSecondaryAlt', this._themeVariant.palette.neutralSecondaryAlt);
|
||||
style.setProperty('--tw-fui-neutralTertiary', this._themeVariant.palette.neutralTertiary);
|
||||
style.setProperty('--tw-fui-neutralTertiaryAlt', this._themeVariant.palette.neutralTertiaryAlt);
|
||||
style.setProperty('--tw-fui-neutralQuaternary', this._themeVariant.palette.neutralQuaternary);
|
||||
style.setProperty('--tw-fui-neutralQuaternaryAlt', this._themeVariant.palette.neutralQuaternaryAlt);
|
||||
style.setProperty('--tw-fui-neutralLight', this._themeVariant.palette.neutralLight);
|
||||
style.setProperty('--tw-fui-neutralLighter', this._themeVariant.palette.neutralLighter);
|
||||
style.setProperty('--tw-fui-neutralLighterAlt', this._themeVariant.palette.neutralLighterAlt);
|
||||
style.setProperty('--tw-fui-accent', this._themeVariant.palette.accent);
|
||||
style.setProperty('--tw-fui-white', this._themeVariant.palette.white);
|
||||
style.setProperty('--tw-fui-whiteTranslucent40', this._themeVariant.palette.whiteTranslucent40);
|
||||
style.setProperty('--tw-fui-yellow', this._themeVariant.palette.yellow);
|
||||
style.setProperty('--tw-fui-yellowLight', this._themeVariant.palette.yellowLight);
|
||||
style.setProperty('--tw-fui-orange', this._themeVariant.palette.orange);
|
||||
style.setProperty('--tw-fui-orangeLight', this._themeVariant.palette.orangeLight);
|
||||
style.setProperty('--tw-fui-orangeLighter', this._themeVariant.palette.orangeLighter);
|
||||
style.setProperty('--tw-fui-redDark', this._themeVariant.palette.redDark);
|
||||
style.setProperty('--tw-fui-red', this._themeVariant.palette.red);
|
||||
style.setProperty('--tw-fui-magentaDark', this._themeVariant.palette.magentaDark);
|
||||
style.setProperty('--tw-fui-magenta', this._themeVariant.palette.magenta);
|
||||
style.setProperty('--tw-fui-magentaLight', this._themeVariant.palette.magentaLight);
|
||||
style.setProperty('--tw-fui-purpleDark', this._themeVariant.palette.purpleDark);
|
||||
style.setProperty('--tw-fui-purple', this._themeVariant.palette.purple);
|
||||
style.setProperty('--tw-fui-purpleLight', this._themeVariant.palette.purpleLight);
|
||||
style.setProperty('--tw-fui-blueDark', this._themeVariant.palette.blueDark);
|
||||
style.setProperty('--tw-fui-blueMid', this._themeVariant.palette.blueMid);
|
||||
style.setProperty('--tw-fui-blue', this._themeVariant.palette.blue);
|
||||
style.setProperty('--tw-fui-blueLight', this._themeVariant.palette.blueLight);
|
||||
style.setProperty('--tw-fui-tealDark', this._themeVariant.palette.tealDark);
|
||||
style.setProperty('--tw-fui-teal', this._themeVariant.palette.teal);
|
||||
style.setProperty('--tw-fui-tealLight', this._themeVariant.palette.tealLight);
|
||||
style.setProperty('--tw-fui-greenDark', this._themeVariant.palette.greenDark);
|
||||
style.setProperty('--tw-fui-green', this._themeVariant.palette.green);
|
||||
style.setProperty('--tw-fui-greenLight', this._themeVariant.palette.greenLight);
|
||||
|
||||
style.setProperty('--tw-fui-bodyBackground', this._themeVariant.semanticColors.bodyBackground);
|
||||
style.setProperty('--tw-fui-bodyStandoutBackground', this._themeVariant.semanticColors.bodyStandoutBackground);
|
||||
style.setProperty('--tw-fui-bodyFrameBackground', this._themeVariant.semanticColors.bodyFrameBackground);
|
||||
style.setProperty('--tw-fui-bodyFrameDivider', this._themeVariant.semanticColors.bodyFrameDivider);
|
||||
style.setProperty('--tw-fui-bodyText', this._themeVariant.semanticColors.bodyText);
|
||||
style.setProperty('--tw-fui-bodyTextChecked', this._themeVariant.semanticColors.bodyTextChecked);
|
||||
style.setProperty('--tw-fui-bodySubtext', this._themeVariant.semanticColors.bodySubtext);
|
||||
style.setProperty('--tw-fui-bodyDivider', this._themeVariant.semanticColors.bodyDivider);
|
||||
style.setProperty('--tw-fui-disabledBackground', this._themeVariant.semanticColors.disabledBackground);
|
||||
style.setProperty('--tw-fui-disabledText', this._themeVariant.semanticColors.disabledText);
|
||||
style.setProperty('--tw-fui-disabledSubtext', this._themeVariant.semanticColors.disabledSubtext);
|
||||
style.setProperty('--tw-fui-disabledBodyText', this._themeVariant.semanticColors.disabledBodyText);
|
||||
style.setProperty('--tw-fui-disabledBodySubtext', this._themeVariant.semanticColors.disabledBodySubtext);
|
||||
style.setProperty('--tw-fui-focusBorder', this._themeVariant.semanticColors.focusBorder);
|
||||
style.setProperty('--tw-fui-variantBorder', this._themeVariant.semanticColors.variantBorder);
|
||||
style.setProperty('--tw-fui-variantBorderHovered', this._themeVariant.semanticColors.variantBorderHovered);
|
||||
style.setProperty('--tw-fui-defaultStateBackground', this._themeVariant.semanticColors.defaultStateBackground);
|
||||
style.setProperty('--tw-fui-errorText', this._themeVariant.semanticColors.errorText);
|
||||
style.setProperty('--tw-fui-warningText', this._themeVariant.semanticColors.warningText);
|
||||
style.setProperty('--tw-fui-errorBackground', this._themeVariant.semanticColors.errorBackground);
|
||||
style.setProperty('--tw-fui-blockingBackground', this._themeVariant.semanticColors.blockingBackground);
|
||||
style.setProperty('--tw-fui-warningBackground', this._themeVariant.semanticColors.warningBackground);
|
||||
style.setProperty('--tw-fui-warningHighlight', this._themeVariant.semanticColors.warningHighlight);
|
||||
style.setProperty('--tw-fui-successBackground', this._themeVariant.semanticColors.successBackground);
|
||||
style.setProperty('--tw-fui-inputBorder', this._themeVariant.semanticColors.inputBorder);
|
||||
style.setProperty('--tw-fui-inputBorderHovered', this._themeVariant.semanticColors.inputBorderHovered);
|
||||
style.setProperty('--tw-fui-inputBackground', this._themeVariant.semanticColors.inputBackground);
|
||||
style.setProperty('--tw-fui-inputBackgroundChecked', this._themeVariant.semanticColors.inputBackgroundChecked);
|
||||
style.setProperty('--tw-fui-inputBackgroundCheckedHovered', this._themeVariant.semanticColors.inputBackgroundCheckedHovered);
|
||||
style.setProperty('--tw-fui-inputForegroundChecked', this._themeVariant.semanticColors.inputForegroundChecked);
|
||||
style.setProperty('--tw-fui-inputFocusBorderAlt', this._themeVariant.semanticColors.inputFocusBorderAlt);
|
||||
style.setProperty('--tw-fui-smallInputBorder', this._themeVariant.semanticColors.smallInputBorder);
|
||||
style.setProperty('--tw-fui-inputText', this._themeVariant.semanticColors.inputText);
|
||||
style.setProperty('--tw-fui-inputTextHovered', this._themeVariant.semanticColors.inputTextHovered);
|
||||
style.setProperty('--tw-fui-inputPlaceholderText', this._themeVariant.semanticColors.inputPlaceholderText);
|
||||
style.setProperty('--tw-fui-buttonBackground', this._themeVariant.semanticColors.buttonBackground);
|
||||
style.setProperty('--tw-fui-buttonBackgroundChecked', this._themeVariant.semanticColors.buttonBackgroundChecked);
|
||||
style.setProperty('--tw-fui-buttonBackgroundHovered', this._themeVariant.semanticColors.buttonBackgroundHovered);
|
||||
style.setProperty('--tw-fui-buttonBackgroundCheckedHovered', this._themeVariant.semanticColors.buttonBackgroundCheckedHovered);
|
||||
style.setProperty('--tw-fui-buttonBackgroundPressed', this._themeVariant.semanticColors.buttonBackgroundPressed);
|
||||
style.setProperty('--tw-fui-buttonBackgroundDisabled', this._themeVariant.semanticColors.buttonBackgroundDisabled);
|
||||
style.setProperty('--tw-fui-buttonBorder', this._themeVariant.semanticColors.buttonBorder);
|
||||
style.setProperty('--tw-fui-buttonText', this._themeVariant.semanticColors.buttonText);
|
||||
style.setProperty('--tw-fui-buttonTextHovered', this._themeVariant.semanticColors.buttonTextHovered);
|
||||
style.setProperty('--tw-fui-buttonTextChecked', this._themeVariant.semanticColors.buttonTextChecked);
|
||||
style.setProperty('--tw-fui-buttonTextCheckedHovered', this._themeVariant.semanticColors.buttonTextCheckedHovered);
|
||||
style.setProperty('--tw-fui-buttonTextPressed', this._themeVariant.semanticColors.buttonTextPressed);
|
||||
style.setProperty('--tw-fui-buttonTextDisabled', this._themeVariant.semanticColors.buttonTextDisabled);
|
||||
style.setProperty('--tw-fui-buttonBorderDisabled', this._themeVariant.semanticColors.buttonBorderDisabled);
|
||||
style.setProperty('--tw-fui-primaryButtonBackground', this._themeVariant.semanticColors.primaryButtonBackground);
|
||||
style.setProperty('--tw-fui-primaryButtonBackgroundHovered', this._themeVariant.semanticColors.primaryButtonBackgroundHovered);
|
||||
style.setProperty('--tw-fui-primaryButtonBackgroundPressed', this._themeVariant.semanticColors.primaryButtonBackgroundPressed);
|
||||
style.setProperty('--tw-fui-primaryButtonBackgroundDisabled', this._themeVariant.semanticColors.primaryButtonBackgroundDisabled);
|
||||
style.setProperty('--tw-fui-primaryButtonBorder', this._themeVariant.semanticColors.primaryButtonBorder);
|
||||
style.setProperty('--tw-fui-primaryButtonText', this._themeVariant.semanticColors.primaryButtonText);
|
||||
style.setProperty('--tw-fui-primaryButtonTextHovered', this._themeVariant.semanticColors.primaryButtonTextHovered);
|
||||
style.setProperty('--tw-fui-primaryButtonTextPressed', this._themeVariant.semanticColors.primaryButtonTextPressed);
|
||||
style.setProperty('--tw-fui-primaryButtonTextDisabled', this._themeVariant.semanticColors.primaryButtonTextDisabled);
|
||||
style.setProperty('--tw-fui-accentButtonBackground', this._themeVariant.semanticColors.accentButtonBackground);
|
||||
style.setProperty('--tw-fui-accentButtonText', this._themeVariant.semanticColors.accentButtonText);
|
||||
style.setProperty('--tw-fui-menuBackground', this._themeVariant.semanticColors.menuBackground);
|
||||
style.setProperty('--tw-fui-menuDivider', this._themeVariant.semanticColors.menuDivider);
|
||||
style.setProperty('--tw-fui-menuIcon', this._themeVariant.semanticColors.menuIcon);
|
||||
style.setProperty('--tw-fui-menuHeader', this._themeVariant.semanticColors.menuHeader);
|
||||
style.setProperty('--tw-fui-menuItemBackgroundHovered', this._themeVariant.semanticColors.menuItemBackgroundHovered);
|
||||
style.setProperty('--tw-fui-menuItemBackgroundPressed', this._themeVariant.semanticColors.menuItemBackgroundPressed);
|
||||
style.setProperty('--tw-fui-menuItemText', this._themeVariant.semanticColors.menuItemText);
|
||||
style.setProperty('--tw-fui-menuItemTextHovered', this._themeVariant.semanticColors.menuItemTextHovered);
|
||||
style.setProperty('--tw-fui-listBackground', this._themeVariant.semanticColors.listBackground);
|
||||
style.setProperty('--tw-fui-listText', this._themeVariant.semanticColors.listText);
|
||||
style.setProperty('--tw-fui-listItemBackgroundHovered', this._themeVariant.semanticColors.listItemBackgroundHovered);
|
||||
style.setProperty('--tw-fui-listItemBackgroundChecked', this._themeVariant.semanticColors.listItemBackgroundChecked);
|
||||
style.setProperty('--tw-fui-listItemBackgroundCheckedHovered', this._themeVariant.semanticColors.listItemBackgroundCheckedHovered);
|
||||
style.setProperty('--tw-fui-listHeaderBackgroundHovered', this._themeVariant.semanticColors.listHeaderBackgroundHovered);
|
||||
style.setProperty('--tw-fui-listHeaderBackgroundPressed', this._themeVariant.semanticColors.listHeaderBackgroundPressed);
|
||||
style.setProperty('--tw-fui-actionLink', this._themeVariant.semanticColors.actionLink);
|
||||
style.setProperty('--tw-fui-actionLinkHovered', this._themeVariant.semanticColors.actionLinkHovered);
|
||||
style.setProperty('--tw-fui-link', this._themeVariant.semanticColors.link);
|
||||
style.setProperty('--tw-fui-linkHovered', this._themeVariant.semanticColors.linkHovered);
|
||||
style.setProperty('--tw-fui-listTextColor', this._themeVariant.semanticColors.listTextColor);
|
||||
style.setProperty('--tw-fui-menuItemBackgroundChecked', this._themeVariant.semanticColors.menuItemBackgroundChecked);
|
||||
|
||||
}
|
||||
|
||||
public render(): void {
|
||||
const element: React.ReactElement<IHelloTailwindCssProps> = React.createElement(
|
||||
HelloTailwindCss,
|
||||
{
|
||||
description: this.properties.description
|
||||
}
|
||||
);
|
||||
|
||||
ReactDom.render(element, this.domElement);
|
||||
}
|
||||
|
||||
protected onDispose(): void {
|
||||
ReactDom.unmountComponentAtNode(this.domElement);
|
||||
}
|
||||
|
||||
protected get dataVersion(): Version {
|
||||
return Version.parse('1.0');
|
||||
}
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
header: {
|
||||
description: strings.PropertyPaneDescription
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
groupName: strings.BasicGroupName,
|
||||
groupFields: [
|
||||
PropertyPaneTextField('description', {
|
||||
label: strings.DescriptionFieldLabel
|
||||
})
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import * as React from 'react';
|
||||
import { escape } from '@microsoft/sp-lodash-subset';
|
||||
import './../../../tailwind.css';
|
||||
import User, { IUserProps } from './User';
|
||||
|
||||
export interface IDocumentCardProps {
|
||||
title: string;
|
||||
documentImageUrl: string;
|
||||
lastEditUserInfo: IUserProps;
|
||||
}
|
||||
|
||||
export default class DocumentCard extends React.Component<IDocumentCardProps, {}> {
|
||||
public render(): React.ReactElement<IDocumentCardProps> {
|
||||
return (
|
||||
<div className="max-w-sm overflow-hidden bg-white text-black border border-solid border-gray-400 hover:outline-none hover:shadow-lg hover:cursor-pointer">
|
||||
<img className="w-full border-0 border-solid border-b border-gray-400" src={this.props.documentImageUrl} alt="Document Preview" />
|
||||
<div className="px-4 py-3 pt-1">
|
||||
<div className="text-lg mb-2">{this.props.title}</div>
|
||||
<User profileImageUrl={this.props.lastEditUserInfo.profileImageUrl}
|
||||
line1={this.props.lastEditUserInfo.line1}
|
||||
line2={this.props.lastEditUserInfo.line1} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
import * as React from 'react';
|
||||
import { IHelloTailwindCssProps } from './IHelloTailwindCssProps';
|
||||
import { escape } from '@microsoft/sp-lodash-subset';
|
||||
import './../../../tailwind.css';
|
||||
import DocumentCard from './DocumentCard';
|
||||
import HorizontalCard from './HorizontalCard';
|
||||
import { Stack } from 'office-ui-fabric-react';
|
||||
|
||||
export default class HelloTailwindCss extends React.Component<IHelloTailwindCssProps, {}> {
|
||||
public render(): React.ReactElement<IHelloTailwindCssProps> {
|
||||
return (
|
||||
<Stack gap="20">
|
||||
<DocumentCard title="Revenue stream proposal fiscal year 2016 version02.pptx"
|
||||
documentImageUrl="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-react-assets/document-preview.png"
|
||||
lastEditUserInfo={{
|
||||
profileImageUrl: "https://static2.sharepointonline.com/files/fabric/office-ui-fabric-react-assets/persona-female.png",
|
||||
line1: "Annie Lindqvist",
|
||||
line2: "Created a few minutes ago"
|
||||
}}
|
||||
/>
|
||||
<HorizontalCard title="Can coffee make you a better developer?"
|
||||
description="Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptatibus quia, nulla! Maiores et perferendis eaque, exercitationem praesentium nihil."
|
||||
documentImageUrl="//tailwindcss.com/img/card-left.jpg"
|
||||
lastEditUserInfo={{
|
||||
profileImageUrl: "https://static2.sharepointonline.com/files/fabric/office-ui-fabric-react-assets/persona-female.png",
|
||||
line1: "Annie Lindqvist",
|
||||
line2: "Aug 18"
|
||||
}}
|
||||
/></Stack>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
import * as React from 'react';
|
||||
import { escape } from '@microsoft/sp-lodash-subset';
|
||||
import './../../../tailwind.css';
|
||||
import User, { IUserProps } from './User';
|
||||
|
||||
export interface IHorizontalCardProps {
|
||||
title: string;
|
||||
description: string;
|
||||
documentImageUrl: string;
|
||||
lastEditUserInfo: IUserProps;
|
||||
}
|
||||
|
||||
const rootClassName = "sp-col-1/3:max-w-sm sp-col-1:max-w-full sp-col-1:flex overflow-hidden shadow hover:outline-none hover:shadow-lg hover:cursor-pointer";
|
||||
|
||||
export default class HorizontalCard extends React.Component<IHorizontalCardProps, {}> {
|
||||
public render(): React.ReactElement<IHorizontalCardProps> {
|
||||
return (
|
||||
<div className={rootClassName}>
|
||||
<div className="h-48 sp-col-1:h-auto sp-col-1:w-48 flex-none bg-cover text-center overflow-hidden" style={{ backgroundImage: "url('//tailwindcss.com/img/card-left.jpg')" }} title="Woman holding a mug">
|
||||
</div>
|
||||
<div className="border-r border-b border-l border-gray-400 sp-col-1:border-l-0 sp-col-1:border-t bg-buttonBackground text-buttonText p-4 flex flex-col justify-between leading-normal">
|
||||
<div className="mb-8">
|
||||
<div className="font-bold text-xl mb-2">{this.props.title}</div>
|
||||
<p className="text-base text-buttonTextDisabled">{this.props.description}</p>
|
||||
</div>
|
||||
<User profileImageUrl={this.props.lastEditUserInfo.profileImageUrl}
|
||||
line1={this.props.lastEditUserInfo.line1}
|
||||
line2={this.props.lastEditUserInfo.line1} />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
export interface IHelloTailwindCssProps {
|
||||
description: string;
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
import * as React from 'react';
|
||||
import { escape } from '@microsoft/sp-lodash-subset';
|
||||
import './../../../tailwind.css';
|
||||
|
||||
export interface IUserProps {
|
||||
profileImageUrl: string;
|
||||
line1: string;
|
||||
line2: string;
|
||||
}
|
||||
|
||||
export default class User extends React.Component<IUserProps, {}> {
|
||||
public render(): React.ReactElement<IUserProps> {
|
||||
return (
|
||||
<div className="flex mt-4">
|
||||
<img className="h-8 w-8 rounded-full mr-2" src={this.props.profileImageUrl} />
|
||||
<div className="text-left">
|
||||
<div className="font-bold text-xs">{this.props.line1}</div>
|
||||
<div className="text-xs text-buttonTextDisabled">{this.props.line2}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
define([], function() {
|
||||
return {
|
||||
"PropertyPaneDescription": "Description",
|
||||
"BasicGroupName": "Group Name",
|
||||
"DescriptionFieldLabel": "Description Field"
|
||||
}
|
||||
});
|
|
@ -0,0 +1,10 @@
|
|||
declare interface IHelloTailwindCssWebPartStrings {
|
||||
PropertyPaneDescription: string;
|
||||
BasicGroupName: string;
|
||||
DescriptionFieldLabel: string;
|
||||
}
|
||||
|
||||
declare module 'HelloTailwindCssWebPartStrings' {
|
||||
const strings: IHelloTailwindCssWebPartStrings;
|
||||
export = strings;
|
||||
}
|
|
@ -0,0 +1,289 @@
|
|||
const plugin = require('tailwindcss/plugin');
|
||||
const customSpSectionVariant = ['sp-col-1', 'sp-col-1/2', 'sp-col-1/3', 'sp-col-2/3'];
|
||||
|
||||
module.exports = {
|
||||
purge: {
|
||||
enabled: true,
|
||||
content: ['./src/**/*.tsx'],
|
||||
options: {
|
||||
whitelistPatterns: [/^CanvasSection*/]
|
||||
}
|
||||
},
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
themeDarker: 'var(--tw-fui-themeDarker)',
|
||||
themeDark: 'var(--tw-fui-themeDark)',
|
||||
themeDarkAlt: 'var(--tw-fui-themeDarkAlt)',
|
||||
themePrimary: 'var(--tw-fui-themePrimary)',
|
||||
themeSecondary: 'var(--tw-fui-themeSecondary)',
|
||||
themeTertiary: 'var(--tw-fui-themeTertiary)',
|
||||
themeLight: 'var(--tw-fui-themeLight)',
|
||||
themeLighter: 'var(--tw-fui-themeLighter)',
|
||||
themeLighterAlt: 'var(--tw-fui-themeLighterAlt)',
|
||||
//black: 'var(--tw-fui-black)',
|
||||
blackTranslucent40: 'var(--tw-fui-blackTranslucent40)',
|
||||
neutralDark: 'var(--tw-fui-neutralDark)',
|
||||
neutralPrimary: 'var(--tw-fui-neutralPrimary)',
|
||||
neutralPrimaryAlt: 'var(--tw-fui-neutralPrimaryAlt)',
|
||||
neutralSecondary: 'var(--tw-fui-neutralSecondary)',
|
||||
neutralSecondaryAlt: 'var(--tw-fui-neutralSecondaryAlt)',
|
||||
neutralTertiary: 'var(--tw-fui-neutralTertiary)',
|
||||
neutralTertiaryAlt: 'var(--tw-fui-neutralTertiaryAlt)',
|
||||
neutralQuaternary: 'var(--tw-fui-neutralQuaternary)',
|
||||
neutralQuaternaryAlt: 'var(--tw-fui-neutralQuaternaryAlt)',
|
||||
neutralLight: 'var(--tw-fui-neutralLight)',
|
||||
neutralLighter: 'var(--tw-fui-neutralLighter)',
|
||||
neutralLighterAlt: 'var(--tw-fui-neutralLighterAlt)',
|
||||
accent: 'var(--tw-fui-accent)',
|
||||
//white: 'var(--tw-fui-white)',
|
||||
whiteTranslucent40: 'var(--tw-fui-whiteTranslucent40)',
|
||||
yellow: 'var(--tw-fui-yellow)',
|
||||
yellowLight: 'var(--tw-fui-yellowLight)',
|
||||
orange: 'var(--tw-fui-orange)',
|
||||
orangeLight: 'var(--tw-fui-orangeLight)',
|
||||
orangeLighter: 'var(--tw-fui-orangeLighter)',
|
||||
redDark: 'var(--tw-fui-redDark)',
|
||||
red: 'var(--tw-fui-red)',
|
||||
magentaDark: 'var(--tw-fui-magentaDark)',
|
||||
magenta: 'var(--tw-fui-magenta)',
|
||||
magentaLight: 'var(--tw-fui-magentaLight)',
|
||||
purpleDark: 'var(--tw-fui-purpleDark)',
|
||||
purple: 'var(--tw-fui-purple)',
|
||||
purpleLight: 'var(--tw-fui-purpleLight)',
|
||||
blueDark: 'var(--tw-fui-blueDark)',
|
||||
blueMid: 'var(--tw-fui-blueMid)',
|
||||
blue: 'var(--tw-fui-blue)',
|
||||
blueLight: 'var(--tw-fui-blueLight)',
|
||||
tealDark: 'var(--tw-fui-tealDark)',
|
||||
teal: 'var(--tw-fui-teal)',
|
||||
tealLight: 'var(--tw-fui-tealLight)',
|
||||
greenDark: 'var(--tw-fui-greenDark)',
|
||||
green: 'var(--tw-fui-green)',
|
||||
greenLight: 'var(--tw-fui-greenLight)',
|
||||
/* ***** */
|
||||
bodyBackground: 'var(--tw-fui-bodyBackground)',
|
||||
bodyStandoutBackground: 'var(--tw-fui-bodyStandoutBackground)',
|
||||
bodyFrameBackground: 'var(--tw-fui-bodyFrameBackground)',
|
||||
bodyFrameDivider: 'var(--tw-fui-bodyFrameDivider)',
|
||||
bodyText: 'var(--tw-fui-bodyText)',
|
||||
bodyTextChecked: 'var(--tw-fui-bodyTextChecked)',
|
||||
bodySubtext: 'var(--tw-fui-bodySubtext)',
|
||||
bodyDivider: 'var(--tw-fui-bodyDivider)',
|
||||
disabledBackground: 'var(--tw-fui-disabledBackground)',
|
||||
disabledText: 'var(--tw-fui-disabledText)',
|
||||
disabledSubtext: 'var(--tw-fui-disabledSubtext)',
|
||||
disabledBodyText: 'var(--tw-fui-disabledBodyText)',
|
||||
disabledBodySubtext: 'var(--tw-fui-disabledBodySubtext)',
|
||||
focusBorder: 'var(--tw-fui-focusBorder)',
|
||||
variantBorder: 'var(--tw-fui-variantBorder)',
|
||||
variantBorderHovered: 'var(--tw-fui-variantBorderHovered)',
|
||||
defaultStateBackground: 'var(--tw-fui-defaultStateBackground)',
|
||||
errorText: 'var(--tw-fui-errorText)',
|
||||
warningText: 'var(--tw-fui-warningText)',
|
||||
errorBackground: 'var(--tw-fui-errorBackground)',
|
||||
blockingBackground: 'var(--tw-fui-blockingBackground)',
|
||||
warningBackground: 'var(--tw-fui-warningBackground)',
|
||||
warningHighlight: 'var(--tw-fui-warningHighlight)',
|
||||
successBackground: 'var(--tw-fui-successBackground)',
|
||||
inputBorder: 'var(--tw-fui-inputBorder)',
|
||||
inputBorderHovered: 'var(--tw-fui-inputBorderHovered)',
|
||||
inputBackground: 'var(--tw-fui-inputBackground)',
|
||||
inputBackgroundChecked: 'var(--tw-fui-inputBackgroundChecked)',
|
||||
inputBackgroundCheckedHovered: 'var(--tw-fui-inputBackgroundCheckedHovered)',
|
||||
inputForegroundChecked: 'var(--tw-fui-inputForegroundChecked)',
|
||||
inputFocusBorderAlt: 'var(--tw-fui-inputFocusBorderAlt)',
|
||||
smallInputBorder: 'var(--tw-fui-smallInputBorder)',
|
||||
inputText: 'var(--tw-fui-inputText)',
|
||||
inputTextHovered: 'var(--tw-fui-inputTextHovered)',
|
||||
inputPlaceholderText: 'var(--tw-fui-inputPlaceholderText)',
|
||||
buttonBackground: 'var(--tw-fui-buttonBackground)',
|
||||
buttonBackgroundChecked: 'var(--tw-fui-buttonBackgroundChecked)',
|
||||
buttonBackgroundHovered: 'var(--tw-fui-buttonBackgroundHovered)',
|
||||
buttonBackgroundCheckedHovered: 'var(--tw-fui-buttonBackgroundCheckedHovered)',
|
||||
buttonBackgroundPressed: 'var(--tw-fui-buttonBackgroundPressed)',
|
||||
buttonBackgroundDisabled: 'var(--tw-fui-buttonBackgroundDisabled)',
|
||||
buttonBorder: 'var(--tw-fui-buttonBorder)',
|
||||
buttonText: 'var(--tw-fui-buttonText)',
|
||||
buttonTextHovered: 'var(--tw-fui-buttonTextHovered)',
|
||||
buttonTextChecked: 'var(--tw-fui-buttonTextChecked)',
|
||||
buttonTextCheckedHovered: 'var(--tw-fui-buttonTextCheckedHovered)',
|
||||
buttonTextPressed: 'var(--tw-fui-buttonTextPressed)',
|
||||
buttonTextDisabled: 'var(--tw-fui-buttonTextDisabled)',
|
||||
buttonBorderDisabled: 'var(--tw-fui-buttonBorderDisabled)',
|
||||
primaryButtonBackground: 'var(--tw-fui-primaryButtonBackground)',
|
||||
primaryButtonBackgroundHovered: 'var(--tw-fui-primaryButtonBackgroundHovered)',
|
||||
primaryButtonBackgroundPressed: 'var(--tw-fui-primaryButtonBackgroundPressed)',
|
||||
primaryButtonBackgroundDisabled: 'var(--tw-fui-primaryButtonBackgroundDisabled)',
|
||||
primaryButtonBorder: 'var(--tw-fui-primaryButtonBorder)',
|
||||
primaryButtonText: 'var(--tw-fui-primaryButtonText)',
|
||||
primaryButtonTextHovered: 'var(--tw-fui-primaryButtonTextHovered)',
|
||||
primaryButtonTextPressed: 'var(--tw-fui-primaryButtonTextPressed)',
|
||||
primaryButtonTextDisabled: 'var(--tw-fui-primaryButtonTextDisabled)',
|
||||
accentButtonBackground: 'var(--tw-fui-accentButtonBackground)',
|
||||
accentButtonText: 'var(--tw-fui-accentButtonText)',
|
||||
menuBackground: 'var(--tw-fui-menuBackground)',
|
||||
menuDivider: 'var(--tw-fui-menuDivider)',
|
||||
menuIcon: 'var(--tw-fui-menuIcon)',
|
||||
menuHeader: 'var(--tw-fui-menuHeader)',
|
||||
menuItemBackgroundHovered: 'var(--tw-fui-menuItemBackgroundHovered)',
|
||||
menuItemBackgroundPressed: 'var(--tw-fui-menuItemBackgroundPressed)',
|
||||
menuItemText: 'var(--tw-fui-menuItemText)',
|
||||
menuItemTextHovered: 'var(--tw-fui-menuItemTextHovered)',
|
||||
listBackground: 'var(--tw-fui-listBackground)',
|
||||
listText: 'var(--tw-fui-listText)',
|
||||
listItemBackgroundHovered: 'var(--tw-fui-listItemBackgroundHovered)',
|
||||
listItemBackgroundChecked: 'var(--tw-fui-listItemBackgroundChecked)',
|
||||
listItemBackgroundCheckedHovered: 'var(--tw-fui-listItemBackgroundCheckedHovered)',
|
||||
listHeaderBackgroundHovered: 'var(--tw-fui-listHeaderBackgroundHovered)',
|
||||
listHeaderBackgroundPressed: 'var(--tw-fui-listHeaderBackgroundPressed)',
|
||||
actionLink: 'var(--tw-fui-actionLink)',
|
||||
actionLinkHovered: 'var(--tw-fui-actionLinkHovered)',
|
||||
link: 'var(--tw-fui-link)',
|
||||
linkHovered: 'var(--tw-fui-linkHovered)',
|
||||
listTextColor: 'var(--tw-fui-listTextColor)',
|
||||
menuItemBackgroundChecked: 'var(--tw-fui-menuItemBackgroundChecked)',
|
||||
}
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
accessibility: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
alignContent: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
alignItems: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
alignSelf: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
appearance: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
backgroundAttachment: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
backgroundClip: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
backgroundColor: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
backgroundImage: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
gradientColorStops: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
backgroundOpacity: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
backgroundPosition: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
backgroundRepeat: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
backgroundSize: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
borderCollapse: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
borderColor: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
borderOpacity: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
borderRadius: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
borderStyle: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
borderWidth: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
boxShadow: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
boxSizing: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
container: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
cursor: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
display: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
divideColor: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
divideOpacity: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
divideStyle: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
divideWidth: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
fill: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
flex: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
flexDirection: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
flexGrow: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
flexShrink: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
flexWrap: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
float: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
clear: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
fontFamily: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
fontSize: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
fontSmoothing: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
fontVariantNumeric: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
fontStyle: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
fontWeight: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
height: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
inset: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
justifyContent: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
justifyItems: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
justifySelf: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
letterSpacing: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
lineHeight: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
listStylePosition: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
listStyleType: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
margin: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
maxHeight: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
maxWidth: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
minHeight: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
minWidth: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
objectFit: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
objectPosition: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
opacity: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
order: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
outline: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
overflow: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
overscrollBehavior: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
padding: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
placeContent: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
placeItems: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
placeSelf: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
placeholderColor: customSpSectionVariant.concat(['focus']),
|
||||
placeholderOpacity: customSpSectionVariant.concat(['focus']),
|
||||
pointerEvents: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
position: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
resize: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
space: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
stroke: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
strokeWidth: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
tableLayout: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
textAlign: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
textColor: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
textOpacity: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
textDecoration: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
textTransform: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
userSelect: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
verticalAlign: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
visibility: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
whitespace: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
width: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
wordBreak: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
zIndex: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
gap: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
gridAutoFlow: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
gridTemplateColumns: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
gridColumn: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
gridColumnStart: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
gridColumnEnd: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
gridTemplateRows: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
gridRow: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
gridRowStart: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
gridRowEnd: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
transform: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
transformOrigin: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
scale: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
rotate: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
translate: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
skew: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
transitionProperty: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
transitionTimingFunction: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
transitionDuration: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
transitionDelay: customSpSectionVariant.concat(['hover', 'focus']),
|
||||
animation: customSpSectionVariant
|
||||
},
|
||||
plugins: [
|
||||
plugin(function ({ addVariant, e }) {
|
||||
addVariant('sp-col-1', ({ modifySelectors, separator }) => {
|
||||
modifySelectors(({ className }) => {
|
||||
return `.CanvasSection.CanvasSection-col.CanvasSection-xl12 .${e(`sp-col-1${separator}${className}`)}`
|
||||
})
|
||||
}),
|
||||
addVariant('sp-col-1/2', ({ modifySelectors, separator }) => {
|
||||
modifySelectors(({ className }) => {
|
||||
return `.CanvasSection.CanvasSection-col.CanvasSection-xl6 .${e(`sp-col-1/2${separator}${className}`)}`
|
||||
})
|
||||
}),
|
||||
addVariant('sp-col-1/3', ({ modifySelectors, separator }) => {
|
||||
modifySelectors(({ className }) => {
|
||||
return `.CanvasSection.CanvasSection-col.CanvasSection-xl4 .${e(`sp-col-1/3${separator}${className}`)}`
|
||||
})
|
||||
}),
|
||||
addVariant('sp-col-2/3', ({ modifySelectors, separator }) => {
|
||||
modifySelectors(({ className }) => {
|
||||
return `.CanvasSection.CanvasSection-col.CanvasSection-xl8 .${e(`sp-col-2/3${separator}${className}`)}`
|
||||
})
|
||||
})
|
||||
})
|
||||
],
|
||||
future: {
|
||||
removeDeprecatedGapUtilities: true,
|
||||
purgeLayersByDefault: true
|
||||
}
|
||||
};
|
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 383 B |
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.3/includes/tsconfig-web.json",
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"jsx": "react",
|
||||
"declaration": true,
|
||||
"sourceMap": true,
|
||||
"experimentalDecorators": true,
|
||||
"skipLibCheck": true,
|
||||
"outDir": "lib",
|
||||
"inlineSources": false,
|
||||
"strictNullChecks": false,
|
||||
"noUnusedLocals": false,
|
||||
"typeRoots": [
|
||||
"./node_modules/@types",
|
||||
"./node_modules/@microsoft"
|
||||
],
|
||||
"types": [
|
||||
"es6-promise",
|
||||
"webpack-env"
|
||||
],
|
||||
"lib": [
|
||||
"es5",
|
||||
"dom",
|
||||
"es2015.collection"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.tsx"
|
||||
],
|
||||
"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
|
||||
}
|
||||
}
|
|
@ -16,7 +16,7 @@
|
|||
"environment": "spo",
|
||||
"framework": "react",
|
||||
"isCreatingSolution": true,
|
||||
"version": "1.7.1",
|
||||
"version": "1.11.0",
|
||||
"libraryName": "react-tenant-properties",
|
||||
"libraryId": "d5bc38a6-0b5c-4644-9087-efa6de87ece1",
|
||||
"packageManager": "npm",
|
||||
|
|
|
@ -1,28 +1,35 @@
|
|||
# React Tenant Properties Web Part
|
||||
|
||||
## Summary
|
||||
|
||||
This web part allows tenant administrators to manage tenant properties through a graphical interface.
|
||||
We can create, edit or delete tenant properties.
|
||||
|
||||
Only users with Tenant Admin Role are allowed to managed tenant properties.
|
||||
#### User without Tenant Admin Role got this message
|
||||
|
||||
### User without Tenant Admin Role got this message
|
||||
|
||||
![tenant properties](./assets/TenantProperties5.jpg)
|
||||
#### List tenant properties
|
||||
|
||||
### List tenant properties
|
||||
|
||||
![tenant properties](./assets/TenantProperties1.jpg)
|
||||
|
||||
#### Add Tenant property
|
||||
### Add Tenant property
|
||||
|
||||
![tenant properties](./assets/TenantProperties2.jpg)
|
||||
|
||||
#### Edit tenant property
|
||||
### Edit tenant property
|
||||
|
||||
![tenant properties](./assets/TenantProperties3.jpg)
|
||||
|
||||
#### Delete tenant property
|
||||
![tenant properties](./assets/TenantProperties4.jpg)
|
||||
### Delete tenant property
|
||||
|
||||
![tenant properties](./assets/TenantProperties4.jpg)
|
||||
|
||||
## Used SharePoint Framework Version
|
||||
|
||||
![drop](https://img.shields.io/badge/version-1.7.1-green.svg)
|
||||
![SPFx 1.11](https://img.shields.io/badge/version-1.11.0-green.svg)
|
||||
|
||||
## Applies to
|
||||
|
||||
|
@ -38,6 +45,7 @@ WebPart Title| Text| no|
|
|||
|
||||
|
||||
## Solution
|
||||
|
||||
The Web Part Use MSGraph API and need to SharePoint Administrator approve de scope "Directory.ReadWrite.All" in SharePoint Admin Center.
|
||||
|
||||
Solution|Author(s)
|
||||
|
@ -49,8 +57,10 @@ Tenant Properties WebPart|João Mendes
|
|||
Version|Date|Comments
|
||||
-------|----|--------
|
||||
1.0.0|Mar 08, 2019|Initial release
|
||||
1.0.1|October 20, 2020|Update to SPFx 1.11.0
|
||||
|
||||
## 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.**
|
||||
|
||||
---
|
||||
|
@ -63,7 +73,7 @@ Version|Date|Comments
|
|||
- `gulp build`
|
||||
- `gulp bundle --ship`
|
||||
- `gulp package-solution --ship`
|
||||
- `Add to AppCatalog and deploy`
|
||||
- `Approve API permission on SharePoint Admin Center`
|
||||
- Add to AppCatalog and deploy
|
||||
- Approve API permission on SharePoint Admin Center
|
||||
|
||||
<img src="https://telemetry.sharepointpnp.com/sp-dev-fx-webparts/samples/react-tenant-properties" />
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"solution": {
|
||||
"name": "react-tenant-properties-client-side-solution",
|
||||
"id": "d5bc38a6-0b5c-4644-9087-efa6de87ece1",
|
||||
"version": "1.0.0.0",
|
||||
"version": "1.0.1.0",
|
||||
"includeClientSideAssets": true,
|
||||
"skipFeatureDeployment": true,
|
||||
"webApiPermissionRequests": [
|
||||
|
@ -11,7 +11,14 @@
|
|||
"resource": "Microsoft Graph",
|
||||
"scope": "Directory.ReadWrite.All"
|
||||
}
|
||||
]
|
||||
],
|
||||
"developer": {
|
||||
"name": "Contoso",
|
||||
"privacyUrl": "https://contoso.com/privacy",
|
||||
"termsOfUseUrl": "https://contoso.com/terms-of-use",
|
||||
"websiteUrl": "https://contoso.com/my-app",
|
||||
"mpnId": "000000"
|
||||
}
|
||||
},
|
||||
"paths": {
|
||||
"zippedPackage": "solution/react-tenant-properties.sppkg"
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
"name": "react-tenant-properties",
|
||||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"main": "lib/index.js",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
},
|
||||
|
@ -15,30 +16,29 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@microsoft/office-ui-fabric-react-bundle": "^1.7.1",
|
||||
"@microsoft/sp-core-library": "1.7.1",
|
||||
"@microsoft/sp-lodash-subset": "1.7.1",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.7.1",
|
||||
"@microsoft/sp-webpart-base": "1.7.1",
|
||||
"@microsoft/sp-core-library": "1.11.0",
|
||||
"@microsoft/sp-lodash-subset": "1.11.0",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.11.0",
|
||||
"@microsoft/sp-property-pane": "1.11.0",
|
||||
"@microsoft/sp-webpart-base": "1.11.0",
|
||||
"@pnp/pnpjs": "^1.3.0",
|
||||
"@pnp/spfx-controls-react": "1.12.0",
|
||||
"@pnp/spfx-property-controls": "1.14.1",
|
||||
"@types/es6-promise": "0.0.33",
|
||||
"@types/jquery": "^3.3.29",
|
||||
"@types/react": "16.4.2",
|
||||
"@types/react-dom": "16.0.5",
|
||||
"@types/webpack-env": "1.13.1",
|
||||
"jquery": "^3.3.1",
|
||||
"react": "16.3.2",
|
||||
"react-dom": "16.3.2"
|
||||
"office-ui-fabric-react": "6.214.0",
|
||||
"react": "16.8.5",
|
||||
"react-dom": "16.8.5"
|
||||
},
|
||||
"resolutions": {
|
||||
"@types/react": "16.4.2"
|
||||
"@types/react": "16.8.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/sp-build-web": "1.7.1",
|
||||
"@microsoft/sp-module-interfaces": "1.7.1",
|
||||
"@microsoft/sp-tslint-rules": "1.7.1",
|
||||
"@microsoft/sp-webpart-workbench": "1.7.1",
|
||||
"@microsoft/rush-stack-compiler-3.3": "0.3.5",
|
||||
"@microsoft/sp-build-web": "1.11.0",
|
||||
"@microsoft/sp-module-interfaces": "1.11.0",
|
||||
"@microsoft/sp-tslint-rules": "1.11.0",
|
||||
"@microsoft/sp-webpart-workbench": "1.11.0",
|
||||
"@types/chai": "3.4.34",
|
||||
"@types/mocha": "2.2.38",
|
||||
"@voitanos/jest-preset-spfx-react16": "^1.1.0",
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// Components that allow authors to embed arbitrary script code should set this to true.
|
||||
// https://support.office.com/en-us/article/Turn-scripting-capabilities-on-or-off-1f2c515f-5d7e-448a-9fd7-835da935584f
|
||||
"requiresCustomScript": false,
|
||||
"supportedHosts": ["SharePointWebPart"],
|
||||
|
||||
"preconfiguredEntries": [{
|
||||
"groupId": "5c03119e-3074-46fd-976b-c60198311f70", // Other
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import * as React from 'react';
|
||||
import * as ReactDom from 'react-dom';
|
||||
import { Version } from '@microsoft/sp-core-library';
|
||||
import {
|
||||
BaseClientSideWebPart,
|
||||
IPropertyPaneConfiguration,
|
||||
PropertyPaneTextField
|
||||
} from '@microsoft/sp-webpart-base';
|
||||
import { BaseClientSideWebPart } from "@microsoft/sp-webpart-base";
|
||||
import { IPropertyPaneConfiguration, PropertyPaneTextField } from "@microsoft/sp-property-pane";
|
||||
|
||||
import * as strings from 'TenantPropertiesWebPartStrings';
|
||||
import TenantProperties from './components/TenantProperties';
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import {IListViewItems } from "./IListViewItems";
|
||||
import { WebPartContext } from '@microsoft/sp-webpart-base';
|
||||
import { SyntheticEvent } from "react";
|
||||
export enum panelMode {
|
||||
"New",
|
||||
"edit",
|
||||
|
@ -10,6 +11,6 @@ export interface ITenantPropertyPanelProps {
|
|||
mode:panelMode;
|
||||
showPanel: boolean;
|
||||
TenantProperty: IListViewItems ;
|
||||
onDismiss(refresh?:boolean) : void;
|
||||
onDismiss(ev?: SyntheticEvent<HTMLElement, Event>, refresh?: boolean) : void;
|
||||
context: WebPartContext;
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss';
|
||||
@import '~office-ui-fabric-react/dist/sass/References.scss';
|
||||
|
||||
.tenantProperties {
|
||||
.container {
|
||||
|
|
|
@ -19,6 +19,7 @@ import { MessageBar, MessageBarType } from 'office-ui-fabric-react/lib/MessageBa
|
|||
import { Spinner, SpinnerSize } from 'office-ui-fabric-react/lib/Spinner';
|
||||
import { WebPartTitle } from "@pnp/spfx-controls-react/lib/WebPartTitle";
|
||||
import * as strings from 'TenantPropertiesWebPartStrings';
|
||||
import { SyntheticEvent } from 'react';
|
||||
|
||||
// ListView Columns
|
||||
const viewFields: IViewField[] = [
|
||||
|
@ -97,7 +98,7 @@ export default class TenantProperties extends React.Component<ITenantPropertiesP
|
|||
}
|
||||
// Panel Dismiss CallBack
|
||||
// @param refresh refresh list?
|
||||
public async onDismissPanel(refresh?: boolean) {
|
||||
public async onDismissPanel(ev?: SyntheticEvent<HTMLElement, Event>, refresh?: boolean) {
|
||||
this.setState({
|
||||
showPanel: false
|
||||
});
|
||||
|
|
|
@ -58,7 +58,9 @@ export default class TenantPropertyPanel extends React.Component<ITenantProperty
|
|||
Description: this.state.tenantProperty.tenantPropertyDescription,
|
||||
Comment: this.state.tenantProperty.tenantPropertyComment
|
||||
});
|
||||
result ? this.props.onDismiss(true) : null;
|
||||
if (result) {
|
||||
this.props.onDismiss(null, true);
|
||||
}
|
||||
}catch(error){
|
||||
this.setState({errorMessage:error});
|
||||
}
|
||||
|
@ -72,7 +74,9 @@ export default class TenantPropertyPanel extends React.Component<ITenantProperty
|
|||
Description: this.state.tenantProperty.tenantPropertyDescription,
|
||||
Comment: this.state.tenantProperty.tenantPropertyComment
|
||||
});
|
||||
result ? this.props.onDismiss(true) : null;
|
||||
if (result) {
|
||||
this.props.onDismiss(null, true);
|
||||
}
|
||||
}catch(error){
|
||||
this.setState({errorMessage:error});
|
||||
}
|
||||
|
@ -86,7 +90,9 @@ export default class TenantPropertyPanel extends React.Component<ITenantProperty
|
|||
Description: this.state.tenantProperty.tenantPropertyDescription,
|
||||
Comment: this.state.tenantProperty.tenantPropertyComment
|
||||
});
|
||||
result ? this.props.onDismiss(true) : null;
|
||||
if (result) {
|
||||
this.props.onDismiss(null, true);
|
||||
}
|
||||
}catch(error){
|
||||
this.setState({errorMessage:error});
|
||||
}
|
||||
|
|
After Width: | Height: | Size: 2.5 KiB |
After Width: | Height: | Size: 933 B |
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.3/includes/tsconfig-web.json",
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
|
@ -10,6 +11,9 @@
|
|||
"experimentalDecorators": true,
|
||||
"skipLibCheck": true,
|
||||
"outDir": "lib",
|
||||
"inlineSources": false,
|
||||
"strictNullChecks": false,
|
||||
"noUnusedLocals": false,
|
||||
"typeRoots": [
|
||||
"./node_modules/@types",
|
||||
"./node_modules/@microsoft"
|
||||
|
@ -25,7 +29,7 @@
|
|||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts", "src/webparts/tenantProperties/components/TenantPropertyPanel.tsx"
|
||||
"src/**/*.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
|
|
|
@ -0,0 +1,653 @@
|
|||
# Upgrade project react-tenant-properties to v1.11.0
|
||||
|
||||
Date: 10/20/2020
|
||||
|
||||
## Findings
|
||||
|
||||
Following is the list of steps required to upgrade your project to SharePoint Framework version 1.11.0. [Summary](#Summary) of the modifications is included at the end of the report.
|
||||
|
||||
### FN001001 @microsoft/sp-core-library | Required
|
||||
|
||||
Upgrade SharePoint Framework dependency package @microsoft/sp-core-library
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -SE @microsoft/sp-core-library@1.11.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001002 @microsoft/sp-lodash-subset | Required
|
||||
|
||||
Upgrade SharePoint Framework dependency package @microsoft/sp-lodash-subset
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -SE @microsoft/sp-lodash-subset@1.11.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001003 @microsoft/sp-office-ui-fabric-core | Required
|
||||
|
||||
Upgrade SharePoint Framework dependency package @microsoft/sp-office-ui-fabric-core
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -SE @microsoft/sp-office-ui-fabric-core@1.11.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001004 @microsoft/sp-webpart-base | Required
|
||||
|
||||
Upgrade SharePoint Framework dependency package @microsoft/sp-webpart-base
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -SE @microsoft/sp-webpart-base@1.11.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001005 @types/react | Required
|
||||
|
||||
Remove SharePoint Framework dependency package @types/react
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm un -S @types/react
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001006 @types/react-dom | Required
|
||||
|
||||
Remove SharePoint Framework dependency package @types/react-dom
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm un -S @types/react-dom
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001007 @types/webpack-env | Required
|
||||
|
||||
Remove SharePoint Framework dependency package @types/webpack-env
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm un -S @types/webpack-env
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001010 @types/es6-promise | Required
|
||||
|
||||
Remove SharePoint Framework dependency package @types/es6-promise
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm un -S @types/es6-promise
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001021 @microsoft/sp-property-pane | Required
|
||||
|
||||
Install SharePoint Framework dependency package @microsoft/sp-property-pane
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -SE @microsoft/sp-property-pane@1.11.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001022 office-ui-fabric-react | Required
|
||||
|
||||
Install SharePoint Framework dependency package office-ui-fabric-react
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -SE office-ui-fabric-react@6.214.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN002001 @microsoft/sp-build-web | Required
|
||||
|
||||
Upgrade SharePoint Framework dev dependency package @microsoft/sp-build-web
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -DE @microsoft/sp-build-web@1.11.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN002002 @microsoft/sp-module-interfaces | Required
|
||||
|
||||
Upgrade SharePoint Framework dev dependency package @microsoft/sp-module-interfaces
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -DE @microsoft/sp-module-interfaces@1.11.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN002003 @microsoft/sp-webpart-workbench | Required
|
||||
|
||||
Upgrade SharePoint Framework dev dependency package @microsoft/sp-webpart-workbench
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -DE @microsoft/sp-webpart-workbench@1.11.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN002009 @microsoft/sp-tslint-rules | Required
|
||||
|
||||
Upgrade SharePoint Framework dev dependency package @microsoft/sp-tslint-rules
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -DE @microsoft/sp-tslint-rules@1.11.0
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN002013 @types/webpack-env | Required
|
||||
|
||||
Install SharePoint Framework dev dependency package @types/webpack-env
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -DE @types/webpack-env@1.13.1
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN002014 @types/es6-promise | Required
|
||||
|
||||
Install SharePoint Framework dev dependency package @types/es6-promise
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -DE @types/es6-promise@0.0.33
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN002015 @types/react | Required
|
||||
|
||||
Install SharePoint Framework dev dependency package @types/react
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -DE @types/react@16.8.8
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN002016 @types/react-dom | Required
|
||||
|
||||
Install SharePoint Framework dev dependency package @types/react-dom
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -DE @types/react-dom@16.8.3
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN006004 package-solution.json developer | Optional
|
||||
|
||||
In package-solution.json add developer section
|
||||
|
||||
In file [./config/package-solution.json](./config/package-solution.json) update the code as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"solution": {
|
||||
"developer": {
|
||||
"name": "Contoso",
|
||||
"privacyUrl": "https://contoso.com/privacy",
|
||||
"termsOfUseUrl": "https://contoso.com/terms-of-use",
|
||||
"websiteUrl": "https://contoso.com/my-app",
|
||||
"mpnId": "000000"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
File: [./config/package-solution.json](./config/package-solution.json)
|
||||
|
||||
### FN010001 .yo-rc.json version | Recommended
|
||||
|
||||
Update version in .yo-rc.json
|
||||
|
||||
In file [./.yo-rc.json](./.yo-rc.json) update the code as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"version": "1.11.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
File: [./.yo-rc.json](./.yo-rc.json)
|
||||
|
||||
### FN012012 tsconfig.json include property | Required
|
||||
|
||||
Update tsconfig.json include property
|
||||
|
||||
In file [./tsconfig.json](./tsconfig.json) update the code as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"include": [
|
||||
"src/**/*.tsx"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
File: [./tsconfig.json](./tsconfig.json)
|
||||
|
||||
### FN002012 @microsoft/rush-stack-compiler-3.3 | Required
|
||||
|
||||
Install SharePoint Framework dev dependency package @microsoft/rush-stack-compiler-3.3
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -DE @microsoft/rush-stack-compiler-3.3@0.3.5
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN012017 tsconfig.json extends property | Required
|
||||
|
||||
Update tsconfig.json extends property
|
||||
|
||||
In file [./tsconfig.json](./tsconfig.json) update the code as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.3/includes/tsconfig-web.json"
|
||||
}
|
||||
```
|
||||
|
||||
File: [./tsconfig.json](./tsconfig.json)
|
||||
|
||||
### FN016004 Property pane property import change to @microsoft/sp-property-pane | Required
|
||||
|
||||
Refactor the code to import property pane property from the @microsoft/sp-property-pane npm package instead of the @microsoft/sp-webpart-base package
|
||||
|
||||
In file [src/webparts/tenantProperties/TenantPropertiesWebPart.ts](src/webparts/tenantProperties/TenantPropertiesWebPart.ts) update the code as follows:
|
||||
|
||||
```ts
|
||||
import { BaseClientSideWebPart } from "@microsoft/sp-webpart-base";
|
||||
import { IPropertyPaneConfiguration, PropertyPaneTextField } from "@microsoft/sp-property-pane";
|
||||
```
|
||||
|
||||
File: [src/webparts/tenantProperties/TenantPropertiesWebPart.ts:4:1](src/webparts/tenantProperties/TenantPropertiesWebPart.ts)
|
||||
|
||||
### FN020001 @types/react | Required
|
||||
|
||||
Add resolution for package @types/react
|
||||
|
||||
In file [./package.json](./package.json) update the code as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"resolutions": {
|
||||
"@types/react": "16.8.8"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN021001 main | Required
|
||||
|
||||
Add package.json property
|
||||
|
||||
In file [./package.json](./package.json) update the code as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"main": "lib/index.js"
|
||||
}
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001008 react | Required
|
||||
|
||||
Upgrade SharePoint Framework dependency package react
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -SE react@16.8.5
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN001009 react-dom | Required
|
||||
|
||||
Upgrade SharePoint Framework dependency package react-dom
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm i -SE react-dom@16.8.5
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
### FN022001 Scss file import | Required
|
||||
|
||||
Remove scss file import
|
||||
|
||||
In file [src/webparts/tenantProperties/components/TenantProperties.module.scss](src/webparts/tenantProperties/components/TenantProperties.module.scss) update the code as follows:
|
||||
|
||||
```scss
|
||||
@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss'
|
||||
```
|
||||
|
||||
File: [src/webparts/tenantProperties/components/TenantProperties.module.scss](src/webparts/tenantProperties/components/TenantProperties.module.scss)
|
||||
|
||||
### FN022002 Scss file import | Optional
|
||||
|
||||
Add scss file import
|
||||
|
||||
In file [src/webparts/tenantProperties/components/TenantProperties.module.scss](src/webparts/tenantProperties/components/TenantProperties.module.scss) update the code as follows:
|
||||
|
||||
```scss
|
||||
@import '~office-ui-fabric-react/dist/sass/References.scss'
|
||||
```
|
||||
|
||||
File: [src/webparts/tenantProperties/components/TenantProperties.module.scss](src/webparts/tenantProperties/components/TenantProperties.module.scss)
|
||||
|
||||
### FN011011 Web part manifest supportedHosts | Required
|
||||
|
||||
Update the supportedHosts property in the manifest
|
||||
|
||||
In file [src/webparts/tenantProperties/TenantPropertiesWebPart.manifest.json](src/webparts/tenantProperties/TenantPropertiesWebPart.manifest.json) update the code as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"supportedHosts": ["SharePointWebPart"]
|
||||
}
|
||||
```
|
||||
|
||||
File: [src/webparts/tenantProperties/TenantPropertiesWebPart.manifest.json](src/webparts/tenantProperties/TenantPropertiesWebPart.manifest.json)
|
||||
|
||||
### FN012014 tsconfig.json compiler options inlineSources | Required
|
||||
|
||||
Update tsconfig.json inlineSources value
|
||||
|
||||
In file [./tsconfig.json](./tsconfig.json) update the code as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"inlineSources": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
File: [./tsconfig.json](./tsconfig.json)
|
||||
|
||||
### FN012015 tsconfig.json compiler options strictNullChecks | Required
|
||||
|
||||
Update tsconfig.json strictNullChecks value
|
||||
|
||||
In file [./tsconfig.json](./tsconfig.json) update the code as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strictNullChecks": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
File: [./tsconfig.json](./tsconfig.json)
|
||||
|
||||
### FN012016 tsconfig.json compiler options noUnusedLocals | Required
|
||||
|
||||
Update tsconfig.json noUnusedLocals value
|
||||
|
||||
In file [./tsconfig.json](./tsconfig.json) update the code as follows:
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noUnusedLocals": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
File: [./tsconfig.json](./tsconfig.json)
|
||||
|
||||
### FN018001 Web part Microsoft Teams tab resources folder | Optional
|
||||
|
||||
Create folder for Microsoft Teams tab resources
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
mkdir /home/jfmr/dev/github/sp-dev-fx-webparts/samples/react-tenant-properties/teams
|
||||
```
|
||||
|
||||
File: [teams](teams)
|
||||
|
||||
### FN018003 Web part Microsoft Teams tab small icon | Optional
|
||||
|
||||
Create Microsoft Teams tab small icon for the web part
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
cp /home/jfmr/.nvm/versions/node/v10.20.1/lib/node_modules/@pnp/cli-microsoft365/dist/m365/spfx/commands/project/project-upgrade/assets/tab20x20.png /home/jfmr/dev/github/sp-dev-fx-webparts/samples/react-tenant-properties/teams/fe85bc01-3650-4533-9c42-5c078fdd579c_outline.png
|
||||
```
|
||||
|
||||
File: [teams/fe85bc01-3650-4533-9c42-5c078fdd579c_outline.png](teams/fe85bc01-3650-4533-9c42-5c078fdd579c_outline.png)
|
||||
|
||||
### FN018004 Web part Microsoft Teams tab large icon | Optional
|
||||
|
||||
Create Microsoft Teams tab large icon for the web part
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
cp /home/jfmr/.nvm/versions/node/v10.20.1/lib/node_modules/@pnp/cli-microsoft365/dist/m365/spfx/commands/project/project-upgrade/assets/tab96x96.png /home/jfmr/dev/github/sp-dev-fx-webparts/samples/react-tenant-properties/teams/fe85bc01-3650-4533-9c42-5c078fdd579c_color.png
|
||||
```
|
||||
|
||||
File: [teams/fe85bc01-3650-4533-9c42-5c078fdd579c_color.png](teams/fe85bc01-3650-4533-9c42-5c078fdd579c_color.png)
|
||||
|
||||
### FN017001 Run npm dedupe | Optional
|
||||
|
||||
If, after upgrading npm packages, when building the project you have errors similar to: "error TS2345: Argument of type 'SPHttpClientConfiguration' is not assignable to parameter of type 'SPHttpClientConfiguration'", try running 'npm dedupe' to cleanup npm packages.
|
||||
|
||||
Execute the following command:
|
||||
|
||||
```sh
|
||||
npm dedupe
|
||||
```
|
||||
|
||||
File: [./package.json](./package.json)
|
||||
|
||||
## Summary
|
||||
|
||||
### Execute script
|
||||
|
||||
```sh
|
||||
npm i -SE @microsoft/sp-core-library@1.11.0 @microsoft/sp-lodash-subset@1.11.0 @microsoft/sp-office-ui-fabric-core@1.11.0 @microsoft/sp-webpart-base@1.11.0 @microsoft/sp-property-pane@1.11.0 office-ui-fabric-react@6.214.0 react@16.8.5 react-dom@16.8.5
|
||||
npm i -DE @microsoft/sp-build-web@1.11.0 @microsoft/sp-module-interfaces@1.11.0 @microsoft/sp-webpart-workbench@1.11.0 @microsoft/sp-tslint-rules@1.11.0 @types/webpack-env@1.13.1 @types/es6-promise@0.0.33 @types/react@16.8.8 @types/react-dom@16.8.3 @microsoft/rush-stack-compiler-3.3@0.3.5
|
||||
npm un -S @types/react @types/react-dom @types/webpack-env @types/es6-promise
|
||||
npm dedupe
|
||||
mkdir /home/jfmr/dev/github/sp-dev-fx-webparts/samples/react-tenant-properties/teams
|
||||
cp /home/jfmr/.nvm/versions/node/v10.20.1/lib/node_modules/@pnp/cli-microsoft365/dist/m365/spfx/commands/project/project-upgrade/assets/tab20x20.png /home/jfmr/dev/github/sp-dev-fx-webparts/samples/react-tenant-properties/teams/fe85bc01-3650-4533-9c42-5c078fdd579c_outline.png
|
||||
cp /home/jfmr/.nvm/versions/node/v10.20.1/lib/node_modules/@pnp/cli-microsoft365/dist/m365/spfx/commands/project/project-upgrade/assets/tab96x96.png /home/jfmr/dev/github/sp-dev-fx-webparts/samples/react-tenant-properties/teams/fe85bc01-3650-4533-9c42-5c078fdd579c_color.png
|
||||
```
|
||||
|
||||
### Modify files
|
||||
|
||||
#### [./config/package-solution.json](./config/package-solution.json)
|
||||
|
||||
In package-solution.json add developer section:
|
||||
|
||||
```json
|
||||
{
|
||||
"solution": {
|
||||
"developer": {
|
||||
"name": "Contoso",
|
||||
"privacyUrl": "https://contoso.com/privacy",
|
||||
"termsOfUseUrl": "https://contoso.com/terms-of-use",
|
||||
"websiteUrl": "https://contoso.com/my-app",
|
||||
"mpnId": "000000"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### [./.yo-rc.json](./.yo-rc.json)
|
||||
|
||||
Update version in .yo-rc.json:
|
||||
|
||||
```json
|
||||
{
|
||||
"@microsoft/generator-sharepoint": {
|
||||
"version": "1.11.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### [./tsconfig.json](./tsconfig.json)
|
||||
|
||||
Update tsconfig.json include property:
|
||||
|
||||
```json
|
||||
{
|
||||
"include": [
|
||||
"src/**/*.tsx"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
Update tsconfig.json extends property:
|
||||
|
||||
```json
|
||||
{
|
||||
"extends": "./node_modules/@microsoft/rush-stack-compiler-3.3/includes/tsconfig-web.json"
|
||||
}
|
||||
```
|
||||
|
||||
Update tsconfig.json inlineSources value:
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"inlineSources": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Update tsconfig.json strictNullChecks value:
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"strictNullChecks": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Update tsconfig.json noUnusedLocals value:
|
||||
|
||||
```json
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noUnusedLocals": false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
#### [src/webparts/tenantProperties/TenantPropertiesWebPart.ts](src/webparts/tenantProperties/TenantPropertiesWebPart.ts)
|
||||
|
||||
Refactor the code to import property pane property from the @microsoft/sp-property-pane npm package instead of the @microsoft/sp-webpart-base package:
|
||||
|
||||
```ts
|
||||
import { BaseClientSideWebPart } from "@microsoft/sp-webpart-base";
|
||||
import { IPropertyPaneConfiguration, PropertyPaneTextField } from "@microsoft/sp-property-pane";
|
||||
```
|
||||
|
||||
#### [./package.json](./package.json)
|
||||
|
||||
Add resolution for package @types/react:
|
||||
|
||||
```json
|
||||
{
|
||||
"resolutions": {
|
||||
"@types/react": "16.8.8"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Add package.json property:
|
||||
|
||||
```json
|
||||
{
|
||||
"main": "lib/index.js"
|
||||
}
|
||||
```
|
||||
|
||||
#### [src/webparts/tenantProperties/components/TenantProperties.module.scss](src/webparts/tenantProperties/components/TenantProperties.module.scss)
|
||||
|
||||
Remove scss file import:
|
||||
|
||||
```scss
|
||||
@import '~@microsoft/sp-office-ui-fabric-core/dist/sass/SPFabricCore.scss'
|
||||
```
|
||||
|
||||
Add scss file import:
|
||||
|
||||
```scss
|
||||
@import '~office-ui-fabric-react/dist/sass/References.scss'
|
||||
```
|
||||
|
||||
#### [src/webparts/tenantProperties/TenantPropertiesWebPart.manifest.json](src/webparts/tenantProperties/TenantPropertiesWebPart.manifest.json)
|
||||
|
||||
Update the supportedHosts property in the manifest:
|
||||
|
||||
```json
|
||||
{
|
||||
"supportedHosts": ["SharePointWebPart"]
|
||||
}
|
||||
```
|