Merge pull request #4491 from HarminderSethi/main
This commit is contained in:
commit
80358cc5de
|
@ -1,7 +1,7 @@
|
|||
// For more information on how to run this SPFx project in a VS Code Remote Container, please visit https://aka.ms/spfx-devcontainer
|
||||
{
|
||||
"name": "SPFx 1.16.1",
|
||||
"image": "docker.io/m365pnp/spfx:1.16.1",
|
||||
"name": "SPFx 1.18.2",
|
||||
"image": "docker.io/m365pnp/spfx:1.18.2",
|
||||
// Set *default* container specific settings.json values on container create.
|
||||
"settings": {},
|
||||
// Add the IDs of extensions you want installed when the container is created.
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
v18.17.1
|
|
@ -5,9 +5,9 @@
|
|||
"nodeVersion": "16.16.0",
|
||||
"sdksVersions": {
|
||||
"@microsoft/microsoft-graph-client": "3.0.2",
|
||||
"@microsoft/teams-js": "2.4.1"
|
||||
"@microsoft/teams-js": "2.12.2"
|
||||
},
|
||||
"version": "1.16.1",
|
||||
"version": "1.18.2",
|
||||
"libraryName": "holidays-calendar",
|
||||
"libraryId": "c85f1137-142e-4570-b3c9-3cdc47580452",
|
||||
"environment": "spo",
|
||||
|
|
|
@ -26,8 +26,8 @@ ACE card extension provides below functionalities
|
|||
|
||||
This sample is optimally compatible with the following environment configuration:
|
||||
|
||||
![SPFx 1.16.1](https://img.shields.io/badge/SPFx-1.16.1-green.svg)
|
||||
![Node.js v16 | v14 | v12](https://img.shields.io/badge/Node.js-v16%20%7C%20v14%20%7C%20v12-green.svg)
|
||||
![SPFx 1.18.2](https://img.shields.io/badge/SPFx-1.18.2-green.svg)
|
||||
![Node.js v18 | v18](https://img.shields.io/badge/Node.js-v18%20%7C%20v16-green.svg)
|
||||
![Compatible with SharePoint Online](https://img.shields.io/badge/SharePoint%20Online-Compatible-green.svg)
|
||||
![Does not work with SharePoint 2019](https://img.shields.io/badge/SharePoint%20Server%202019-Incompatible-red.svg "SharePoint Server 2019 requires SPFx 1.4.1 or lower")
|
||||
![Does not work with SharePoint 2016 (Feature Pack 2)](https://img.shields.io/badge/SharePoint%20Server%202016%20(Feature%20Pack%202)-Incompatible-red.svg "SharePoint Server 2016 Feature Pack 2 requires SPFx 1.1")
|
||||
|
@ -58,6 +58,7 @@ For more information about SPFx compatibility, please refer to <https://aka.ms/s
|
|||
| Version | Date | Comments |
|
||||
| ------- | ---------------- | --------------- |
|
||||
| 1.0 | January 29, 2021 | Initial release |
|
||||
| 1.1 | November 30, 2023 | Upgraded to SPFx 1.18.2 |
|
||||
|
||||
## Minimal Path to Awesome
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
"Holiday calendar solution contains SPFx web part and Adaptive card extension for Viva connections."
|
||||
],
|
||||
"creationDateTime": "2023-01-09",
|
||||
"updateDateTime": "2023-01-09",
|
||||
"updateDateTime": "2023-11-30",
|
||||
"products": [
|
||||
"SharePoint"
|
||||
],
|
||||
|
@ -21,7 +21,7 @@
|
|||
},
|
||||
{
|
||||
"key": "SPFX-VERSION",
|
||||
"value": "1.16.1"
|
||||
"value": "1.18.2"
|
||||
}
|
||||
],
|
||||
"thumbnails": [
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
"solution": {
|
||||
"name": "holidays-calendar",
|
||||
"id": "c85f1137-142e-4570-b3c9-3cdc47580452",
|
||||
"version": "1.0.0.0",
|
||||
"version": "1.1.0.0",
|
||||
"includeClientSideAssets": true,
|
||||
"skipFeatureDeployment": true,
|
||||
"webApiPermissionRequests": [
|
||||
|
@ -45,7 +45,7 @@
|
|||
"title": "holidays-calendar Feature",
|
||||
"description": "The feature that activates elements of the holidays-calendar solution.",
|
||||
"id": "182f7879-26d6-4fb6-b5ad-9f34a54ba79d",
|
||||
"version": "1.0.0.0"
|
||||
"version": "1.1.0.0"
|
||||
|
||||
}
|
||||
]
|
||||
|
|
|
@ -2,5 +2,5 @@
|
|||
"$schema": "https://developer.microsoft.com/json-schemas/spfx-build/spfx-serve.schema.json",
|
||||
"port": 4321,
|
||||
"https": true,
|
||||
"initialPage": "https://enter-your-SharePoint-site/_layouts/workbench.aspx"
|
||||
"initialPage":"https://{tenantDomain}/_layouts/workbench.aspx"
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"name": "holidays-calendar",
|
||||
"version": "0.0.1",
|
||||
"version": "1.1",
|
||||
"private": true,
|
||||
"engines": {
|
||||
"node": ">=16.13.0 <17.0.0"
|
||||
"node": ">=16.13.0 <17.0.0 || >=18.17.1 <19.0.0"
|
||||
},
|
||||
"main": "lib/index.js",
|
||||
"scripts": {
|
||||
|
@ -13,13 +13,15 @@
|
|||
"serve": "gulp bundle --custom-serve --max_old_space_size=4096 && fast-serve"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fluentui/react-components": "^9.7.4",
|
||||
"@microsoft/generator-sharepoint": "^1.16.1",
|
||||
"@microsoft/sp-core-library": "1.16.1",
|
||||
"@microsoft/sp-lodash-subset": "1.16.1",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.16.1",
|
||||
"@microsoft/sp-property-pane": "1.16.1",
|
||||
"@microsoft/sp-webpart-base": "1.16.1",
|
||||
"@fluentui/react": "8.106.4",
|
||||
"@fluentui/react-components": "^9.42.0",
|
||||
"@microsoft/generator-sharepoint": "^1.18.2",
|
||||
"@microsoft/sp-adaptive-card-extension-base": "1.18.2",
|
||||
"@microsoft/sp-core-library": "1.18.2",
|
||||
"@microsoft/sp-lodash-subset": "1.18.2",
|
||||
"@microsoft/sp-office-ui-fabric-core": "1.18.2",
|
||||
"@microsoft/sp-property-pane": "1.18.2",
|
||||
"@microsoft/sp-webpart-base": "1.18.2",
|
||||
"@pnp/core": "^3.10.0",
|
||||
"@pnp/graph": "^3.10.0",
|
||||
"@pnp/logging": "^3.10.0",
|
||||
|
@ -27,27 +29,27 @@
|
|||
"@pnp/sp": "^3.10.0",
|
||||
"json-to-csv-export": "^2.1.1",
|
||||
"moment": "^2.29.4",
|
||||
"office-ui-fabric-react": "^7.199.1",
|
||||
"react": "17.0.1",
|
||||
"react-dom": "17.0.1",
|
||||
"tslib": "2.3.1",
|
||||
"@microsoft/sp-adaptive-card-extension-base": "1.16.1"
|
||||
"yarn": "^1.22.21"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@microsoft/eslint-config-spfx": "1.16.1",
|
||||
"@microsoft/eslint-plugin-spfx": "1.16.1",
|
||||
"@microsoft/microsoft-graph-types": "^2.25.0",
|
||||
"@microsoft/rush-stack-compiler-4.5": "0.2.2",
|
||||
"@microsoft/sp-build-web": "1.16.1",
|
||||
"@microsoft/sp-module-interfaces": "1.16.1",
|
||||
"@microsoft/eslint-config-spfx": "1.18.2",
|
||||
"@microsoft/eslint-plugin-spfx": "1.18.2",
|
||||
"@microsoft/microsoft-graph-types": "^2.40.0",
|
||||
"@microsoft/rush-stack-compiler-4.7": "0.1.0",
|
||||
"@microsoft/sp-build-web": "1.18.2",
|
||||
"@microsoft/sp-module-interfaces": "1.18.2",
|
||||
"@rushstack/eslint-config": "2.5.1",
|
||||
"@types/react": "17.0.45",
|
||||
"@types/react-dom": "17.0.17",
|
||||
"@types/webpack-env": "~1.15.2",
|
||||
"ajv": "^6.12.5",
|
||||
"eslint": "8.7.0",
|
||||
"eslint-plugin-react-hooks": "4.3.0",
|
||||
"gulp": "4.0.2",
|
||||
"spfx-fast-serve-helpers": "~1.16.0",
|
||||
"typescript": "4.5.5"
|
||||
"spfx-fast-serve-helpers": "~1.18.2",
|
||||
"typescript": "4.7.4"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,15 +14,15 @@ import { IEmployeeInfo } from "../../webparts/holidaysCalendar/interfaces/IHolid
|
|||
import { ItemFailureQuickView } from "./quickView/ItemFailureQuickView";
|
||||
|
||||
export interface IHolidayViewAdaptiveCardExtensionProps {
|
||||
title: string;
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface IHolidayViewAdaptiveCardExtensionState {
|
||||
holidayItems: IHolidayItem[];
|
||||
listItems: IHoliday[];
|
||||
currentIndex: number;
|
||||
holidayService: HolidaysCalendarService;
|
||||
employeeInfo: IEmployeeInfo;
|
||||
holidayItems: IHolidayItem[];
|
||||
listItems: IHoliday[];
|
||||
currentIndex: number;
|
||||
holidayService: HolidaysCalendarService;
|
||||
employeeInfo: IEmployeeInfo;
|
||||
}
|
||||
|
||||
const CARD_VIEW_REGISTRY_ID: string = "HolidayView_CARD_VIEW";
|
||||
|
@ -30,53 +30,53 @@ export const QUICK_VIEW_REGISTRY_ID: string = "HolidayView_QUICK_VIEW";
|
|||
export const ITEMSUCCESS_QUICK_VIEW_REGISTRY_ID: string = "ItemSuccess_Quick_VIEW";
|
||||
export const ITEMFAILURE_QUICK_VIEW_REGISTRY_ID: string = "ItemFailure_Quick_VIEW";
|
||||
export default class HolidayViewAdaptiveCardExtension extends BaseAdaptiveCardExtension<
|
||||
IHolidayViewAdaptiveCardExtensionProps,
|
||||
IHolidayViewAdaptiveCardExtensionState
|
||||
IHolidayViewAdaptiveCardExtensionProps,
|
||||
IHolidayViewAdaptiveCardExtensionState
|
||||
> {
|
||||
private _deferredPropertyPane: HolidayViewPropertyPane | undefined;
|
||||
private spService: SPService;
|
||||
private graphService: GraphService;
|
||||
private holidayService: HolidaysCalendarService;
|
||||
public async onInit(): Promise<void> {
|
||||
this.spService = new SPService(this.context);
|
||||
this.graphService = new GraphService(this.context);
|
||||
this.holidayService = new HolidaysCalendarService(this.spService, this.graphService);
|
||||
const employeeInfo = await this.holidayService.getEmployeeInfo();
|
||||
private _deferredPropertyPane: HolidayViewPropertyPane | undefined;
|
||||
private spService: SPService;
|
||||
private graphService: GraphService;
|
||||
private holidayService: HolidaysCalendarService;
|
||||
public async onInit(): Promise<void> {
|
||||
this.spService = new SPService(this.context);
|
||||
this.graphService = new GraphService(this.context);
|
||||
this.holidayService = new HolidaysCalendarService(this.spService, this.graphService);
|
||||
const employeeInfo = await this.holidayService.getEmployeeInfo();
|
||||
|
||||
const listItems = await this.holidayService.getHolidaysByLocation(employeeInfo.officeLocation);
|
||||
const holidayItems = this.holidayService.getHolidayItemsToRender(listItems);
|
||||
const upcomingHoliday = holidayItems.filter((item) => moment().isBefore(item.holidayDate.value, "days"));
|
||||
const upcomingHolidayIndex = upcomingHoliday.length > 0 ? holidayItems.findIndex((item) => item.Id == upcomingHoliday[0].Id) : 0;
|
||||
const listItems = await this.holidayService.getHolidaysByLocation(employeeInfo.officeLocation);
|
||||
const holidayItems = this.holidayService.getHolidayItemsToRender(listItems);
|
||||
const upcomingHoliday = holidayItems.filter((item) => moment().isBefore(item.holidayDate.value, "days"));
|
||||
const upcomingHolidayIndex = upcomingHoliday.length > 0 ? holidayItems.findIndex((item) => item.Id === upcomingHoliday[0].Id) : 0;
|
||||
|
||||
this.state = {
|
||||
holidayItems: holidayItems,
|
||||
listItems: listItems,
|
||||
currentIndex: upcomingHolidayIndex,
|
||||
holidayService: this.holidayService,
|
||||
employeeInfo: employeeInfo,
|
||||
};
|
||||
this.state = {
|
||||
holidayItems: holidayItems,
|
||||
listItems: listItems,
|
||||
currentIndex: upcomingHolidayIndex,
|
||||
holidayService: this.holidayService,
|
||||
employeeInfo: employeeInfo,
|
||||
};
|
||||
|
||||
this.cardNavigator.register(CARD_VIEW_REGISTRY_ID, () => new CardView());
|
||||
this.quickViewNavigator.register(QUICK_VIEW_REGISTRY_ID, () => new QuickView());
|
||||
this.quickViewNavigator.register(ITEMSUCCESS_QUICK_VIEW_REGISTRY_ID, () => new ItemSuccessQuickView());
|
||||
this.quickViewNavigator.register(ITEMFAILURE_QUICK_VIEW_REGISTRY_ID, () => new ItemFailureQuickView());
|
||||
return Promise.resolve();
|
||||
}
|
||||
this.cardNavigator.register(CARD_VIEW_REGISTRY_ID, () => new CardView());
|
||||
this.quickViewNavigator.register(QUICK_VIEW_REGISTRY_ID, () => new QuickView());
|
||||
this.quickViewNavigator.register(ITEMSUCCESS_QUICK_VIEW_REGISTRY_ID, () => new ItemSuccessQuickView());
|
||||
this.quickViewNavigator.register(ITEMFAILURE_QUICK_VIEW_REGISTRY_ID, () => new ItemFailureQuickView());
|
||||
return Promise.resolve();
|
||||
}
|
||||
|
||||
protected loadPropertyPaneResources(): Promise<void> {
|
||||
return import(
|
||||
/* webpackChunkName: 'HolidayView-property-pane'*/
|
||||
"./HolidayViewPropertyPane"
|
||||
).then((component) => {
|
||||
this._deferredPropertyPane = new component.HolidayViewPropertyPane();
|
||||
});
|
||||
}
|
||||
protected loadPropertyPaneResources(): Promise<void> {
|
||||
return import(
|
||||
/* webpackChunkName: 'HolidayView-property-pane'*/
|
||||
"./HolidayViewPropertyPane"
|
||||
).then((component) => {
|
||||
this._deferredPropertyPane = new component.HolidayViewPropertyPane();
|
||||
});
|
||||
}
|
||||
|
||||
protected renderCard(): string | undefined {
|
||||
return CARD_VIEW_REGISTRY_ID;
|
||||
}
|
||||
protected renderCard(): string | undefined {
|
||||
return CARD_VIEW_REGISTRY_ID;
|
||||
}
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
return this._deferredPropertyPane?.getPropertyPaneConfiguration();
|
||||
}
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
return this._deferredPropertyPane?.getPropertyPaneConfiguration();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,32 @@
|
|||
import { ISPFxAdaptiveCard, BaseAdaptiveCardView, IActionArguments } from "@microsoft/sp-adaptive-card-extension-base";
|
||||
import { ISPFxAdaptiveCard, BaseAdaptiveCardQuickView, IActionArguments } from "@microsoft/sp-adaptive-card-extension-base";
|
||||
|
||||
import { IHolidayViewAdaptiveCardExtensionProps, IHolidayViewAdaptiveCardExtensionState } from "../HolidayViewAdaptiveCardExtension";
|
||||
|
||||
export interface IQuickViewData {
|
||||
holidayTitle: string;
|
||||
detail: string;
|
||||
holidayTitle: string;
|
||||
detail: string;
|
||||
}
|
||||
|
||||
export class ItemFailureQuickView extends BaseAdaptiveCardView<IHolidayViewAdaptiveCardExtensionProps, IHolidayViewAdaptiveCardExtensionState, IQuickViewData> {
|
||||
public get data(): IQuickViewData {
|
||||
return {
|
||||
holidayTitle: this.state.holidayItems[this.state.currentIndex].holidayTitle.label,
|
||||
detail: this.state.holidayItems[this.state.currentIndex].holidayDay.label + " " + this.state.holidayItems[this.state.currentIndex].holidayDate.label,
|
||||
};
|
||||
}
|
||||
public onAction(action: IActionArguments): void {
|
||||
if (action.type === "Submit") {
|
||||
const { id } = action.data;
|
||||
if (id === "back") {
|
||||
this.quickViewNavigator.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
public get template(): ISPFxAdaptiveCard {
|
||||
return require("./template/ItemFailureTemplate.json");
|
||||
}
|
||||
export class ItemFailureQuickView extends BaseAdaptiveCardQuickView<
|
||||
IHolidayViewAdaptiveCardExtensionProps,
|
||||
IHolidayViewAdaptiveCardExtensionState,
|
||||
IQuickViewData
|
||||
> {
|
||||
public get data(): IQuickViewData {
|
||||
return {
|
||||
holidayTitle: this.state.holidayItems[this.state.currentIndex].holidayTitle.label,
|
||||
detail: this.state.holidayItems[this.state.currentIndex].holidayDay.label + " " + this.state.holidayItems[this.state.currentIndex].holidayDate.label,
|
||||
};
|
||||
}
|
||||
public onAction(action: IActionArguments): void {
|
||||
if (action.type === "Submit") {
|
||||
const { id } = action.data;
|
||||
if (id === "back") {
|
||||
this.quickViewNavigator.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
public get template(): ISPFxAdaptiveCard {
|
||||
return require("./template/ItemFailureTemplate.json");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,28 +1,32 @@
|
|||
import { ISPFxAdaptiveCard, BaseAdaptiveCardView, IActionArguments } from "@microsoft/sp-adaptive-card-extension-base";
|
||||
import { ISPFxAdaptiveCard, BaseAdaptiveCardQuickView, IActionArguments } from "@microsoft/sp-adaptive-card-extension-base";
|
||||
|
||||
import { IHolidayViewAdaptiveCardExtensionProps, IHolidayViewAdaptiveCardExtensionState } from "../HolidayViewAdaptiveCardExtension";
|
||||
|
||||
export interface IQuickViewData {
|
||||
holidayTitle: string;
|
||||
detail: string;
|
||||
holidayTitle: string;
|
||||
detail: string;
|
||||
}
|
||||
|
||||
export class ItemSuccessQuickView extends BaseAdaptiveCardView<IHolidayViewAdaptiveCardExtensionProps, IHolidayViewAdaptiveCardExtensionState, IQuickViewData> {
|
||||
public get data(): IQuickViewData {
|
||||
return {
|
||||
holidayTitle: this.state.holidayItems[this.state.currentIndex].holidayTitle.label,
|
||||
detail: this.state.holidayItems[this.state.currentIndex].holidayDay.label + " " + this.state.holidayItems[this.state.currentIndex].holidayDate.label,
|
||||
};
|
||||
}
|
||||
public onAction(action: IActionArguments): void {
|
||||
if (action.type === "Submit") {
|
||||
const { id } = action.data;
|
||||
if (id === "back") {
|
||||
this.quickViewNavigator.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
public get template(): ISPFxAdaptiveCard {
|
||||
return require("./template/ItemSuccessTemplate.json");
|
||||
}
|
||||
export class ItemSuccessQuickView extends BaseAdaptiveCardQuickView<
|
||||
IHolidayViewAdaptiveCardExtensionProps,
|
||||
IHolidayViewAdaptiveCardExtensionState,
|
||||
IQuickViewData
|
||||
> {
|
||||
public get data(): IQuickViewData {
|
||||
return {
|
||||
holidayTitle: this.state.holidayItems[this.state.currentIndex].holidayTitle.label,
|
||||
detail: this.state.holidayItems[this.state.currentIndex].holidayDay.label + " " + this.state.holidayItems[this.state.currentIndex].holidayDate.label,
|
||||
};
|
||||
}
|
||||
public onAction(action: IActionArguments): void {
|
||||
if (action.type === "Submit") {
|
||||
const { id } = action.data;
|
||||
if (id === "back") {
|
||||
this.quickViewNavigator.pop();
|
||||
}
|
||||
}
|
||||
}
|
||||
public get template(): ISPFxAdaptiveCard {
|
||||
return require("./template/ItemSuccessTemplate.json");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,34 +1,34 @@
|
|||
import { ISPFxAdaptiveCard, BaseAdaptiveCardView, IActionArguments } from "@microsoft/sp-adaptive-card-extension-base";
|
||||
import { ISPFxAdaptiveCard, BaseAdaptiveCardQuickView, IActionArguments } from "@microsoft/sp-adaptive-card-extension-base";
|
||||
|
||||
import { IHolidayViewAdaptiveCardExtensionProps, IHolidayViewAdaptiveCardExtensionState } from "../HolidayViewAdaptiveCardExtension";
|
||||
import { ITEMSUCCESS_QUICK_VIEW_REGISTRY_ID, ITEMFAILURE_QUICK_VIEW_REGISTRY_ID } from "../HolidayViewAdaptiveCardExtension";
|
||||
export interface IQuickViewData {
|
||||
holidayTitle: string;
|
||||
detail: string;
|
||||
holidayTitle: string;
|
||||
detail: string;
|
||||
}
|
||||
|
||||
export class QuickView extends BaseAdaptiveCardView<IHolidayViewAdaptiveCardExtensionProps, IHolidayViewAdaptiveCardExtensionState, IQuickViewData> {
|
||||
public get data(): IQuickViewData {
|
||||
return {
|
||||
holidayTitle: this.state.holidayItems[this.state.currentIndex].holidayTitle.label,
|
||||
detail: this.state.holidayItems[this.state.currentIndex].holidayDay.label + " " + this.state.holidayItems[this.state.currentIndex].holidayDate.label,
|
||||
};
|
||||
}
|
||||
public onAction(action: IActionArguments): void {
|
||||
if (action.type === "Submit") {
|
||||
const { id } = action.data;
|
||||
if (id === "addInCalendar") {
|
||||
this.state.holidayService
|
||||
.addLeaveInCalendar(this.state.employeeInfo, this.state.holidayItems[this.state.currentIndex])
|
||||
.then((value) => this.quickViewNavigator.push(ITEMSUCCESS_QUICK_VIEW_REGISTRY_ID))
|
||||
.catch((ex) => {
|
||||
console.log(ex);
|
||||
this.quickViewNavigator.push(ITEMFAILURE_QUICK_VIEW_REGISTRY_ID);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
public get template(): ISPFxAdaptiveCard {
|
||||
return require("./template/QuickViewTemplate.json");
|
||||
}
|
||||
export class QuickView extends BaseAdaptiveCardQuickView<IHolidayViewAdaptiveCardExtensionProps, IHolidayViewAdaptiveCardExtensionState, IQuickViewData> {
|
||||
public get data(): IQuickViewData {
|
||||
return {
|
||||
holidayTitle: this.state.holidayItems[this.state.currentIndex].holidayTitle.label,
|
||||
detail: this.state.holidayItems[this.state.currentIndex].holidayDay.label + " " + this.state.holidayItems[this.state.currentIndex].holidayDate.label,
|
||||
};
|
||||
}
|
||||
public onAction(action: IActionArguments): void {
|
||||
if (action.type === "Submit") {
|
||||
const { id } = action.data;
|
||||
if (id === "addInCalendar") {
|
||||
this.state.holidayService
|
||||
.addLeaveInCalendar(this.state.employeeInfo, this.state.holidayItems[this.state.currentIndex])
|
||||
.then((value) => this.quickViewNavigator.push(ITEMSUCCESS_QUICK_VIEW_REGISTRY_ID))
|
||||
.catch((ex) => {
|
||||
console.log(ex);
|
||||
this.quickViewNavigator.push(ITEMFAILURE_QUICK_VIEW_REGISTRY_ID);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
public get template(): ISPFxAdaptiveCard {
|
||||
return require("./template/QuickViewTemplate.json");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,38 +1,38 @@
|
|||
import { MSGraphClientV3 } from "@microsoft/sp-http-msgraph";
|
||||
|
||||
/* eslint-disable */
|
||||
|
||||
import { Event as IEventType, User } from "@microsoft/microsoft-graph-types";
|
||||
|
||||
import { MSGraphClientV3, GraphRequest } from "@microsoft/sp-http-msgraph";
|
||||
|
||||
export class GraphService {
|
||||
private context: any;
|
||||
private context: any;
|
||||
|
||||
constructor(context: any) {
|
||||
this.context = context;
|
||||
}
|
||||
constructor(context: any) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
private getClient = async (): Promise<MSGraphClientV3> => {
|
||||
return await this.context.msGraphClientFactory.getClient("3");
|
||||
};
|
||||
public getMyInformation = async () => {
|
||||
const client = await this.getClient();
|
||||
const request: GraphRequest = client.api("/me");
|
||||
const employeeInfo: User = await request.get();
|
||||
return Promise.resolve(employeeInfo);
|
||||
};
|
||||
public getMyTimeZone = async (): Promise<string> => {
|
||||
const client = await this.getClient();
|
||||
const request: GraphRequest = client.api("/me/mailboxSettings");
|
||||
const response = await request.get();
|
||||
return Promise.resolve(response.timeZone);
|
||||
};
|
||||
private getClient = async (): Promise<MSGraphClientV3> => {
|
||||
return await this.context.msGraphClientFactory.getClient("3");
|
||||
};
|
||||
public getMyInformation = async () => {
|
||||
const client = await this.getClient();
|
||||
const request = client.api("/me");
|
||||
const employeeInfo: User = await request.get();
|
||||
return Promise.resolve(employeeInfo);
|
||||
};
|
||||
public getMyTimeZone = async (): Promise<string> => {
|
||||
const client = await this.getClient();
|
||||
const request = client.api("/me/mailboxSettings");
|
||||
const response = await request.get();
|
||||
return Promise.resolve(response.timeZone);
|
||||
};
|
||||
|
||||
public createEvent = async (detail: IEventType): Promise<any> => {
|
||||
const client = await this.getClient();
|
||||
const request: GraphRequest = client.api("/me/events");
|
||||
public createEvent = async (detail: IEventType): Promise<any> => {
|
||||
const client = await this.getClient();
|
||||
const request = client.api("/me/events");
|
||||
|
||||
const response = await request.post(detail);
|
||||
const response = await request.post(detail);
|
||||
|
||||
return Promise.resolve(response);
|
||||
};
|
||||
return Promise.resolve(response);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { HolidaysListColumns, HolidaysListSelectColumns } from "../constants/constant";
|
||||
import { ListName } from "../constants/constant";
|
||||
import { GraphService } from "./GraphService";
|
||||
|
@ -9,140 +10,140 @@ import { IEmployeeInfo } from "../../webparts/holidaysCalendar/interfaces/IHolid
|
|||
import { IHolidayItem, IHoliday } from "../interfaces/HolidaysCalendar";
|
||||
|
||||
export class HolidaysCalendarService {
|
||||
private spService: SPService;
|
||||
private graphService: GraphService;
|
||||
constructor(spService: SPService, graphService: GraphService) {
|
||||
this.spService = spService;
|
||||
this.graphService = graphService;
|
||||
}
|
||||
private spService: SPService;
|
||||
private graphService: GraphService;
|
||||
constructor(spService: SPService, graphService: GraphService) {
|
||||
this.spService = spService;
|
||||
this.graphService = graphService;
|
||||
}
|
||||
|
||||
public getHolidayItemsToRender = (items: any[]): IHolidayItem[] => {
|
||||
const holidayItems: IHolidayItem[] = [];
|
||||
items.forEach((item) => {
|
||||
holidayItems.push({
|
||||
holidayTitle: {
|
||||
label: item.Title,
|
||||
},
|
||||
holidayDate: {
|
||||
value: item.Date,
|
||||
label: moment(item.Date).format("MMMM Do"),
|
||||
},
|
||||
holidayDay: {
|
||||
label: moment(item.Date).format("dddd"),
|
||||
},
|
||||
holidayType: {
|
||||
optional: item.Optional,
|
||||
},
|
||||
Id: item.Id,
|
||||
});
|
||||
});
|
||||
return holidayItems;
|
||||
};
|
||||
public getHolidayItemsToRender = (items: any[]): IHolidayItem[] => {
|
||||
const holidayItems: IHolidayItem[] = [];
|
||||
items.forEach((item) => {
|
||||
holidayItems.push({
|
||||
holidayTitle: {
|
||||
label: item.Title,
|
||||
},
|
||||
holidayDate: {
|
||||
value: item.Date,
|
||||
label: moment(item.Date).format("MMMM Do"),
|
||||
},
|
||||
holidayDay: {
|
||||
label: moment(item.Date).format("dddd"),
|
||||
},
|
||||
holidayType: {
|
||||
optional: item.Optional,
|
||||
},
|
||||
Id: item.Id,
|
||||
});
|
||||
});
|
||||
return holidayItems;
|
||||
};
|
||||
|
||||
public getHolidayItemsToRender_ACE = (items: IHoliday[]): IHolidayItem[] => {
|
||||
const holidayItems: IHolidayItem[] = [];
|
||||
items.forEach((item) => {
|
||||
if (moment().isBefore(item.Date, "days")) {
|
||||
holidayItems.push({
|
||||
holidayTitle: {
|
||||
label: item.Title,
|
||||
},
|
||||
holidayDate: {
|
||||
value: item.Date,
|
||||
label: moment(item.Date).format("MMMM Do"),
|
||||
},
|
||||
holidayDay: {
|
||||
label: moment(item.Date).format("dddd"),
|
||||
},
|
||||
holidayType: {
|
||||
optional: item.Optional,
|
||||
},
|
||||
Id: item.Id,
|
||||
});
|
||||
}
|
||||
});
|
||||
return holidayItems;
|
||||
};
|
||||
public getHolidayItemsToRender_ACE = (items: IHoliday[]): IHolidayItem[] => {
|
||||
const holidayItems: IHolidayItem[] = [];
|
||||
items.forEach((item) => {
|
||||
if (moment().isBefore(item.Date, "days")) {
|
||||
holidayItems.push({
|
||||
holidayTitle: {
|
||||
label: item.Title,
|
||||
},
|
||||
holidayDate: {
|
||||
value: item.Date,
|
||||
label: moment(item.Date).format("MMMM Do"),
|
||||
},
|
||||
holidayDay: {
|
||||
label: moment(item.Date).format("dddd"),
|
||||
},
|
||||
holidayType: {
|
||||
optional: item.Optional,
|
||||
},
|
||||
Id: item.Id,
|
||||
});
|
||||
}
|
||||
});
|
||||
return holidayItems;
|
||||
};
|
||||
|
||||
public getHolidaysByLocation = async (location: string): Promise<IHoliday[]> => {
|
||||
const holidays: IHoliday[] = [];
|
||||
const filter = `${HolidaysListColumns.Location} eq '${location}'`;
|
||||
try {
|
||||
const listItems: any[] = await this.spService.getListItems(ListName.Holidays, filter, HolidaysListSelectColumns);
|
||||
public getHolidaysByLocation = async (location: string): Promise<IHoliday[]> => {
|
||||
const holidays: IHoliday[] = [];
|
||||
const filter = `${HolidaysListColumns.Location} eq '${location}'`;
|
||||
try {
|
||||
const listItems: any[] = await this.spService.getListItems(ListName.Holidays, filter, HolidaysListSelectColumns);
|
||||
|
||||
listItems.forEach((listItem: any) => {
|
||||
const holiday: IHoliday = {
|
||||
Id: listItem.Id,
|
||||
Title: listItem.Title ?? null,
|
||||
Date: Boolean(listItem.Date) ? new Date(listItem.Date) : null,
|
||||
Location: listItem.Location ?? null,
|
||||
Optional: listItem.Optional,
|
||||
};
|
||||
holidays.push(holiday);
|
||||
});
|
||||
return Promise.resolve(holidays);
|
||||
} catch (ex) {
|
||||
return Promise.reject(holidays);
|
||||
}
|
||||
};
|
||||
listItems.forEach((listItem: any) => {
|
||||
const holiday: IHoliday = {
|
||||
Id: listItem.Id,
|
||||
Title: listItem.Title ?? null,
|
||||
Date: Boolean(listItem.Date) ? new Date(listItem.Date) : null,
|
||||
Location: listItem.Location ?? null,
|
||||
Optional: listItem.Optional,
|
||||
};
|
||||
holidays.push(holiday);
|
||||
});
|
||||
return Promise.resolve(holidays);
|
||||
} catch (ex) {
|
||||
return Promise.reject(holidays);
|
||||
}
|
||||
};
|
||||
|
||||
public getEmployeeInfo = async (): Promise<IEmployeeInfo> => {
|
||||
const [myInformation, myTimeZone] = await Promise.all([this.graphService.getMyInformation(), this.graphService.getMyTimeZone()]);
|
||||
const employeeInformation = {} as IEmployeeInfo;
|
||||
employeeInformation.eMail = myInformation.mail;
|
||||
employeeInformation.id = myInformation.id;
|
||||
employeeInformation.officeLocation = myInformation.officeLocation;
|
||||
employeeInformation.displayName = myInformation.displayName;
|
||||
employeeInformation.timezone = myTimeZone;
|
||||
return Promise.resolve(employeeInformation);
|
||||
};
|
||||
public addLeaveInCalendar = async (employeeInfo: IEmployeeInfo, item: IHolidayItem): Promise<boolean> => {
|
||||
try {
|
||||
const eventDetail: IEventType = {};
|
||||
eventDetail.subject = item.holidayTitle.label ?? null;
|
||||
eventDetail.start = {
|
||||
dateTime: moment(item.holidayDate.value).format("YYYY-MM-DD") + "T00:00:00",
|
||||
timeZone: employeeInfo.timezone,
|
||||
};
|
||||
eventDetail.end = {
|
||||
dateTime: moment(item.holidayDate.value).format("YYYY-MM-DD") + "T23:59:59",
|
||||
timeZone: employeeInfo.timezone,
|
||||
};
|
||||
eventDetail.showAs = "oof";
|
||||
eventDetail.attendees = [
|
||||
{
|
||||
emailAddress: {
|
||||
address: employeeInfo.eMail,
|
||||
name: employeeInfo.displayName,
|
||||
},
|
||||
},
|
||||
];
|
||||
public getEmployeeInfo = async (): Promise<IEmployeeInfo> => {
|
||||
const [myInformation, myTimeZone] = await Promise.all([this.graphService.getMyInformation(), this.graphService.getMyTimeZone()]);
|
||||
const employeeInformation = {} as IEmployeeInfo;
|
||||
employeeInformation.eMail = myInformation.mail;
|
||||
employeeInformation.id = myInformation.id;
|
||||
employeeInformation.officeLocation = myInformation.officeLocation;
|
||||
employeeInformation.displayName = myInformation.displayName;
|
||||
employeeInformation.timezone = myTimeZone;
|
||||
return Promise.resolve(employeeInformation);
|
||||
};
|
||||
public addLeaveInCalendar = async (employeeInfo: IEmployeeInfo, item: IHolidayItem): Promise<boolean> => {
|
||||
try {
|
||||
const eventDetail: IEventType = {};
|
||||
eventDetail.subject = item.holidayTitle.label ?? null;
|
||||
eventDetail.start = {
|
||||
dateTime: moment(item.holidayDate.value).format("YYYY-MM-DD") + "T00:00:00",
|
||||
timeZone: employeeInfo.timezone,
|
||||
};
|
||||
eventDetail.end = {
|
||||
dateTime: moment(item.holidayDate.value).format("YYYY-MM-DD") + "T23:59:59",
|
||||
timeZone: employeeInfo.timezone,
|
||||
};
|
||||
eventDetail.showAs = "oof";
|
||||
eventDetail.attendees = [
|
||||
{
|
||||
emailAddress: {
|
||||
address: employeeInfo.eMail,
|
||||
name: employeeInfo.displayName,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
await this.graphService.createEvent(eventDetail);
|
||||
return Promise.resolve(true);
|
||||
} catch (ex) {
|
||||
return Promise.reject(false);
|
||||
}
|
||||
};
|
||||
await this.graphService.createEvent(eventDetail);
|
||||
return Promise.resolve(true);
|
||||
} catch (ex) {
|
||||
return Promise.reject(false);
|
||||
}
|
||||
};
|
||||
|
||||
public getItemsToDownloadAsCSV = (items: IHolidayItem[]) => {
|
||||
const itemsToExport: any[] = [];
|
||||
items.forEach((item) => {
|
||||
itemsToExport.push({
|
||||
Title: item.holidayTitle.label,
|
||||
Date: item.holidayDate.label,
|
||||
Day: item.holidayDay.label,
|
||||
IsOptional: item.holidayType.optional ? "Yes" : "No",
|
||||
});
|
||||
});
|
||||
public getItemsToDownloadAsCSV = (items: IHolidayItem[]): any => {
|
||||
const itemsToExport: any[] = [];
|
||||
items.forEach((item) => {
|
||||
itemsToExport.push({
|
||||
Title: item.holidayTitle.label,
|
||||
Date: item.holidayDate.label,
|
||||
Day: item.holidayDay.label,
|
||||
IsOptional: item.holidayType.optional ? "Yes" : "No",
|
||||
});
|
||||
});
|
||||
|
||||
const dataToDownload = {
|
||||
data: itemsToExport,
|
||||
filename: "HolidayCalendar",
|
||||
delimiter: ",",
|
||||
headers: ["Title", "Date", "Day", "IsOptional"],
|
||||
};
|
||||
const dataToDownload = {
|
||||
data: itemsToExport,
|
||||
filename: "HolidayCalendar",
|
||||
delimiter: ",",
|
||||
headers: ["Title", "Date", "Day", "IsOptional"],
|
||||
};
|
||||
|
||||
return dataToDownload;
|
||||
};
|
||||
return dataToDownload;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { SPFI, spfi, SPFx as spSPFx } from "@pnp/sp";
|
||||
|
||||
import "@pnp/sp/webs";
|
||||
|
@ -8,60 +9,60 @@ import "@pnp/sp/items/get-all";
|
|||
import "@pnp/sp/site-users/web";
|
||||
|
||||
export class SPService {
|
||||
private sp: SPFI;
|
||||
constructor(context: any) {
|
||||
this.sp = spfi().using(spSPFx(context));
|
||||
}
|
||||
private sp: SPFI;
|
||||
constructor(context: any) {
|
||||
this.sp = spfi().using(spSPFx(context));
|
||||
}
|
||||
|
||||
public getListItems = async (
|
||||
listTitle: string,
|
||||
filter: string = "",
|
||||
columns: string = "*",
|
||||
expand: string = "",
|
||||
orderby?: string,
|
||||
orderSequence?: boolean
|
||||
): Promise<any> => {
|
||||
let items: any = [];
|
||||
try {
|
||||
if (!orderby) {
|
||||
items = await this.sp.web.lists.getByTitle(listTitle).items.select(columns).filter(filter).expand(expand).top(5000)();
|
||||
} else {
|
||||
return await this.sp.web.lists.getByTitle(listTitle).items.select(columns).orderBy(orderby, orderSequence).filter(filter).expand(expand).top(5000)();
|
||||
}
|
||||
return Promise.resolve(items);
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
};
|
||||
public getListItems = async (
|
||||
listTitle: string,
|
||||
filter: string = "",
|
||||
columns: string = "*",
|
||||
expand: string = "",
|
||||
orderby?: string,
|
||||
orderSequence?: boolean
|
||||
): Promise<any> => {
|
||||
let items: any = [];
|
||||
try {
|
||||
if (!orderby) {
|
||||
items = await this.sp.web.lists.getByTitle(listTitle).items.select(columns).filter(filter).expand(expand).top(5000)();
|
||||
} else {
|
||||
return await this.sp.web.lists.getByTitle(listTitle).items.select(columns).orderBy(orderby, orderSequence).filter(filter).expand(expand).top(5000)();
|
||||
}
|
||||
return Promise.resolve(items);
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
};
|
||||
|
||||
public getSharePointGroupDetails = async (groupTitle: string): Promise<any> => {
|
||||
try {
|
||||
const response = await this.sp.web.siteGroups.getByName(groupTitle)();
|
||||
return Promise.resolve(response);
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
};
|
||||
public getSharePointGroupDetails = async (groupTitle: string): Promise<any> => {
|
||||
try {
|
||||
const response = await this.sp.web.siteGroups.getByName(groupTitle)();
|
||||
return Promise.resolve(response);
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
};
|
||||
|
||||
public getUserDetails = async (userId: number): Promise<any> => {
|
||||
try {
|
||||
const response = await this.sp.web.getUserById(userId)();
|
||||
return Promise.resolve(response);
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
};
|
||||
public getUserDetails = async (userId: number): Promise<any> => {
|
||||
try {
|
||||
const response = await this.sp.web.getUserById(userId)();
|
||||
return Promise.resolve(response);
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
};
|
||||
|
||||
public ensureUser = async (loginName: string): Promise<any> => {
|
||||
if (loginName.indexOf("i:0#.f|membership|") === -1) {
|
||||
loginName = "i:0#.f|membership|" + loginName;
|
||||
}
|
||||
public ensureUser = async (loginName: string): Promise<any> => {
|
||||
if (loginName.indexOf("i:0#.f|membership|") === -1) {
|
||||
loginName = "i:0#.f|membership|" + loginName;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await (await this.sp.web.ensureUser(loginName)).user();
|
||||
return Promise.resolve(response);
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
};
|
||||
try {
|
||||
const response = await (await this.sp.web.ensureUser(loginName)).user();
|
||||
return Promise.resolve(response);
|
||||
} catch (ex) {
|
||||
return Promise.reject(ex);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
import { GraphService } from "./../../common/services/GraphService";
|
||||
import * as React from "react";
|
||||
import * as ReactDom from "react-dom";
|
||||
|
@ -11,132 +12,132 @@ import { IHolidaysCalendarProps } from "./components/IHolidaysCalendarProps";
|
|||
import { SPService } from "../../common/services/SPService";
|
||||
|
||||
export interface IHolidaysCalendarWebPartProps {
|
||||
enableDownload: boolean;
|
||||
title: string;
|
||||
showFixedOptional: boolean;
|
||||
enableDownload: boolean;
|
||||
title: string;
|
||||
showFixedOptional: boolean;
|
||||
}
|
||||
|
||||
export default class HolidaysCalendarWebPart extends BaseClientSideWebPart<IHolidaysCalendarWebPartProps> {
|
||||
private _isDarkTheme: boolean = false;
|
||||
private _environmentMessage: string = "";
|
||||
private spService: SPService;
|
||||
private graphService: GraphService;
|
||||
private _isDarkTheme: boolean = false;
|
||||
private _environmentMessage: string = "";
|
||||
private spService: SPService;
|
||||
private graphService: GraphService;
|
||||
|
||||
public render(): void {
|
||||
const element: React.ReactElement<IHolidaysCalendarProps> = React.createElement(HolidaysCalendar, {
|
||||
isDarkTheme: this._isDarkTheme,
|
||||
environmentMessage: this._environmentMessage,
|
||||
hasTeamsContext: !!this.context.sdks.microsoftTeams,
|
||||
userDisplayName: this.context.pageContext.user.displayName,
|
||||
spService: this.spService,
|
||||
graphService: this.graphService,
|
||||
context: this.context,
|
||||
showDownload: this.properties.enableDownload ?? false,
|
||||
title: this.properties.title,
|
||||
showFixedOptional: this.properties.showFixedOptional,
|
||||
});
|
||||
public render(): void {
|
||||
const element: React.ReactElement<IHolidaysCalendarProps> = React.createElement(HolidaysCalendar, {
|
||||
isDarkTheme: this._isDarkTheme,
|
||||
environmentMessage: this._environmentMessage,
|
||||
hasTeamsContext: !!this.context.sdks.microsoftTeams,
|
||||
userDisplayName: this.context.pageContext.user.displayName,
|
||||
spService: this.spService,
|
||||
graphService: this.graphService,
|
||||
context: this.context,
|
||||
showDownload: this.properties.enableDownload ?? false,
|
||||
title: this.properties.title,
|
||||
showFixedOptional: this.properties.showFixedOptional,
|
||||
});
|
||||
|
||||
ReactDom.render(element, this.domElement);
|
||||
}
|
||||
ReactDom.render(element, this.domElement);
|
||||
}
|
||||
|
||||
protected onInit(): Promise<void> {
|
||||
return this._getEnvironmentMessage().then((message) => {
|
||||
this.spService = new SPService(this.context);
|
||||
this.graphService = new GraphService(this.context);
|
||||
this._environmentMessage = message;
|
||||
});
|
||||
}
|
||||
protected onInit(): Promise<void> {
|
||||
return this._getEnvironmentMessage().then((message) => {
|
||||
this.spService = new SPService(this.context);
|
||||
this.graphService = new GraphService(this.context);
|
||||
this._environmentMessage = message;
|
||||
});
|
||||
}
|
||||
|
||||
private _getEnvironmentMessage(): Promise<string> {
|
||||
if (!!this.context.sdks.microsoftTeams) {
|
||||
// running in Teams, office.com or Outlook
|
||||
return this.context.sdks.microsoftTeams.teamsJs.app.getContext().then((context) => {
|
||||
let environmentMessage: string = "";
|
||||
switch (context.app.host.name) {
|
||||
case "Office": // running in Office
|
||||
environmentMessage = this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentOffice : strings.AppOfficeEnvironment;
|
||||
break;
|
||||
case "Outlook": // running in Outlook
|
||||
environmentMessage = this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentOutlook : strings.AppOutlookEnvironment;
|
||||
break;
|
||||
case "Teams": // running in Teams
|
||||
environmentMessage = this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentTeams : strings.AppTeamsTabEnvironment;
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unknown host");
|
||||
}
|
||||
private _getEnvironmentMessage(): Promise<string> {
|
||||
if (!!this.context.sdks.microsoftTeams) {
|
||||
// running in Teams, office.com or Outlook
|
||||
return this.context.sdks.microsoftTeams.teamsJs.app.getContext().then((context) => {
|
||||
let environmentMessage: string = "";
|
||||
switch (context.app.host.name) {
|
||||
case "Office": // running in Office
|
||||
environmentMessage = this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentOffice : strings.AppOfficeEnvironment;
|
||||
break;
|
||||
case "Outlook": // running in Outlook
|
||||
environmentMessage = this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentOutlook : strings.AppOutlookEnvironment;
|
||||
break;
|
||||
case "Teams": // running in Teams
|
||||
environmentMessage = this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentTeams : strings.AppTeamsTabEnvironment;
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unknown host");
|
||||
}
|
||||
|
||||
return environmentMessage;
|
||||
});
|
||||
}
|
||||
return environmentMessage;
|
||||
});
|
||||
}
|
||||
|
||||
return Promise.resolve(this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentSharePoint : strings.AppSharePointEnvironment);
|
||||
}
|
||||
return Promise.resolve(this.context.isServedFromLocalhost ? strings.AppLocalEnvironmentSharePoint : strings.AppSharePointEnvironment);
|
||||
}
|
||||
|
||||
protected onThemeChanged(currentTheme: IReadonlyTheme | undefined): void {
|
||||
if (!currentTheme) {
|
||||
return;
|
||||
}
|
||||
protected onThemeChanged(currentTheme: IReadonlyTheme | undefined): void {
|
||||
if (!currentTheme) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._isDarkTheme = !!currentTheme.isInverted;
|
||||
const { semanticColors } = currentTheme;
|
||||
this._isDarkTheme = !!currentTheme.isInverted;
|
||||
const { semanticColors } = currentTheme;
|
||||
|
||||
if (semanticColors) {
|
||||
this.domElement.style.setProperty("--bodyText", semanticColors.bodyText || null);
|
||||
this.domElement.style.setProperty("--link", semanticColors.link || null);
|
||||
this.domElement.style.setProperty("--linkHovered", semanticColors.linkHovered || null);
|
||||
}
|
||||
}
|
||||
if (semanticColors) {
|
||||
this.domElement.style.setProperty("--bodyText", semanticColors.bodyText || null);
|
||||
this.domElement.style.setProperty("--link", semanticColors.link || null);
|
||||
this.domElement.style.setProperty("--linkHovered", semanticColors.linkHovered || null);
|
||||
}
|
||||
}
|
||||
|
||||
protected onDispose(): void {
|
||||
ReactDom.unmountComponentAtNode(this.domElement);
|
||||
}
|
||||
protected onDispose(): void {
|
||||
ReactDom.unmountComponentAtNode(this.domElement);
|
||||
}
|
||||
|
||||
protected get dataVersion(): Version {
|
||||
return Version.parse("1.0");
|
||||
}
|
||||
protected get dataVersion(): Version {
|
||||
return Version.parse("1.0");
|
||||
}
|
||||
|
||||
protected onPropertyPaneFieldChanged = (propertyPath: string, oldValue: any, newValue: any): void => {
|
||||
if (propertyPath === "enableDownload" && oldValue !== newValue) {
|
||||
this.properties.enableDownload = newValue;
|
||||
}
|
||||
if (propertyPath === "title" && oldValue !== newValue) {
|
||||
this.properties.title = newValue;
|
||||
}
|
||||
if (propertyPath === "showFixedOptional" && oldValue !== newValue) {
|
||||
this.properties.showFixedOptional = newValue;
|
||||
}
|
||||
};
|
||||
protected onPropertyPaneFieldChanged = (propertyPath: string, oldValue: any, newValue: any): void => {
|
||||
if (propertyPath === "enableDownload" && oldValue !== newValue) {
|
||||
this.properties.enableDownload = newValue;
|
||||
}
|
||||
if (propertyPath === "title" && oldValue !== newValue) {
|
||||
this.properties.title = newValue;
|
||||
}
|
||||
if (propertyPath === "showFixedOptional" && oldValue !== newValue) {
|
||||
this.properties.showFixedOptional = newValue;
|
||||
}
|
||||
};
|
||||
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
header: {
|
||||
description: strings.PropertyPaneDescription,
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
groupName: strings.BasicGroupName,
|
||||
groupFields: [
|
||||
PropertyPaneTextField("title", {
|
||||
label: "Title",
|
||||
}),
|
||||
PropertyPaneToggle("enableDownload", {
|
||||
key: "enableDownload",
|
||||
label: "Show Download Option",
|
||||
checked: false,
|
||||
}),
|
||||
PropertyPaneToggle("showFixedOptional", {
|
||||
key: "showFixedOptional",
|
||||
label: "Show Fixed Optional Icons",
|
||||
checked: false,
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
|
||||
return {
|
||||
pages: [
|
||||
{
|
||||
header: {
|
||||
description: strings.PropertyPaneDescription,
|
||||
},
|
||||
groups: [
|
||||
{
|
||||
groupName: strings.BasicGroupName,
|
||||
groupFields: [
|
||||
PropertyPaneTextField("title", {
|
||||
label: "Title",
|
||||
}),
|
||||
PropertyPaneToggle("enableDownload", {
|
||||
key: "enableDownload",
|
||||
label: "Show Download Option",
|
||||
checked: false,
|
||||
}),
|
||||
PropertyPaneToggle("showFixedOptional", {
|
||||
key: "showFixedOptional",
|
||||
label: "Show Fixed Optional Icons",
|
||||
checked: false,
|
||||
}),
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,71 +7,71 @@ import { IHolidaysCalendarProps } from "./IHolidaysCalendarProps";
|
|||
import { FluentProvider, webLightTheme } from "@fluentui/react-components";
|
||||
import { DismissCircleRegular } from "@fluentui/react-icons";
|
||||
import csvDownload from "json-to-csv-export";
|
||||
const HolidaysCalendar = (props: IHolidaysCalendarProps) => {
|
||||
const [service] = React.useState<HolidaysCalendarService>(new HolidaysCalendarService(props.spService, props.graphService));
|
||||
const HolidaysCalendar = (props: IHolidaysCalendarProps): JSX.Element => {
|
||||
const [service] = React.useState<HolidaysCalendarService>(new HolidaysCalendarService(props.spService, props.graphService));
|
||||
|
||||
const [state, setState] = React.useState<IHolidaysCalendarState>({
|
||||
listItems: [],
|
||||
holidayListItems: [],
|
||||
message: {
|
||||
show: false,
|
||||
intent: "success",
|
||||
},
|
||||
employeeInfo: null,
|
||||
columns: [],
|
||||
});
|
||||
const [state, setState] = React.useState<IHolidaysCalendarState>({
|
||||
listItems: [],
|
||||
holidayListItems: [],
|
||||
message: {
|
||||
show: false,
|
||||
intent: "success",
|
||||
},
|
||||
employeeInfo: null,
|
||||
columns: [],
|
||||
});
|
||||
|
||||
const handleCalenderAddClick = async (itemId: number) => {
|
||||
try {
|
||||
const selectedItem = state.holidayListItems.filter((item) => item.Id === itemId);
|
||||
await service.addLeaveInCalendar(state.employeeInfo, selectedItem[0]);
|
||||
setState((prevState: IHolidaysCalendarState) => ({ ...prevState, message: { show: true, intent: "success" } }));
|
||||
} catch (ex) {
|
||||
setState((prevState: IHolidaysCalendarState) => ({ ...prevState, message: { show: true, intent: "error" } }));
|
||||
}
|
||||
};
|
||||
const handleCalenderAddClick = async (itemId: number): Promise<void> => {
|
||||
try {
|
||||
const selectedItem = state.holidayListItems.filter((item) => item.Id === itemId);
|
||||
await service.addLeaveInCalendar(state.employeeInfo, selectedItem[0]);
|
||||
setState((prevState: IHolidaysCalendarState) => ({ ...prevState, message: { show: true, intent: "success" } }));
|
||||
} catch (ex) {
|
||||
setState((prevState: IHolidaysCalendarState) => ({ ...prevState, message: { show: true, intent: "error" } }));
|
||||
}
|
||||
};
|
||||
|
||||
const handleDismissClick = () => {
|
||||
setState((prevState: IHolidaysCalendarState) => ({ ...prevState, message: { show: false, intent: "success" } }));
|
||||
};
|
||||
const handleDismissClick = (): void => {
|
||||
setState((prevState: IHolidaysCalendarState) => ({ ...prevState, message: { show: false, intent: "success" } }));
|
||||
};
|
||||
|
||||
const handleDownload = () => {
|
||||
const itemsToDownload = service.getItemsToDownloadAsCSV(state.holidayListItems);
|
||||
csvDownload(itemsToDownload);
|
||||
};
|
||||
const handleDownload = (): void => {
|
||||
const itemsToDownload = service.getItemsToDownloadAsCSV(state.holidayListItems);
|
||||
csvDownload(itemsToDownload);
|
||||
};
|
||||
|
||||
/* eslint-disable */
|
||||
React.useEffect(() => {
|
||||
(async () => {
|
||||
const employeeInfo = await service.getEmployeeInfo();
|
||||
/* eslint-disable */
|
||||
React.useEffect(() => {
|
||||
(async () => {
|
||||
const employeeInfo = await service.getEmployeeInfo();
|
||||
|
||||
const listItems = await service.getHolidaysByLocation(employeeInfo.officeLocation);
|
||||
const holidayItems = service.getHolidayItemsToRender(listItems);
|
||||
const listItems = await service.getHolidaysByLocation(employeeInfo.officeLocation);
|
||||
const holidayItems = service.getHolidayItemsToRender(listItems);
|
||||
|
||||
setState((prevState: IHolidaysCalendarState) => ({ ...prevState, listItems: listItems, holidayListItems: holidayItems, employeeInfo: employeeInfo }));
|
||||
})();
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<FluentProvider theme={webLightTheme}>
|
||||
{state.message.show && (
|
||||
<Alert intent={state.message.intent} action={{ icon: <DismissCircleRegular aria-label="dismiss message" onClick={handleDismissClick} /> }}>
|
||||
{state.message.intent === "success" ? "Holiday added in calendar" : "Some error occurred"}
|
||||
</Alert>
|
||||
)}
|
||||
{state.holidayListItems.length > 0 && (
|
||||
<HolidaysList
|
||||
items={state.holidayListItems}
|
||||
onCalendarAddClick={handleCalenderAddClick}
|
||||
onDownloadItems={handleDownload}
|
||||
showDownload={props.showDownload}
|
||||
title={props.title}
|
||||
showFixedOptional={props.showFixedOptional}
|
||||
/>
|
||||
)}
|
||||
</FluentProvider>
|
||||
</>
|
||||
);
|
||||
setState((prevState: IHolidaysCalendarState) => ({ ...prevState, listItems: listItems, holidayListItems: holidayItems, employeeInfo: employeeInfo }));
|
||||
})();
|
||||
}, []);
|
||||
return (
|
||||
<>
|
||||
<FluentProvider theme={webLightTheme}>
|
||||
{state.message.show && (
|
||||
<Alert intent={state.message.intent} action={{ icon: <DismissCircleRegular aria-label="dismiss message" onClick={handleDismissClick} /> }}>
|
||||
{state.message.intent === "success" ? "Holiday added in calendar" : "Some error occurred"}
|
||||
</Alert>
|
||||
)}
|
||||
{state.holidayListItems.length > 0 && (
|
||||
<HolidaysList
|
||||
items={state.holidayListItems}
|
||||
onCalendarAddClick={handleCalenderAddClick}
|
||||
onDownloadItems={handleDownload}
|
||||
showDownload={props.showDownload}
|
||||
title={props.title}
|
||||
showFixedOptional={props.showFixedOptional}
|
||||
/>
|
||||
)}
|
||||
</FluentProvider>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default HolidaysCalendar;
|
||||
|
|
|
@ -1,130 +1,129 @@
|
|||
import * as React from "react";
|
||||
import { IHolidaysListProps } from "../../../../common/interfaces/HolidaysCalendar";
|
||||
import {
|
||||
ColumnDefinition,
|
||||
createColumn,
|
||||
DataGrid,
|
||||
DataGridBody,
|
||||
DataGridCell,
|
||||
DataGridHeader,
|
||||
DataGridHeaderCell,
|
||||
DataGridRow,
|
||||
RowState,
|
||||
TableCell,
|
||||
TableCellActions,
|
||||
TableCellLayout,
|
||||
} from "@fluentui/react-components/unstable";
|
||||
DataGrid,
|
||||
DataGridBody,
|
||||
DataGridCell,
|
||||
DataGridHeader,
|
||||
DataGridHeaderCell,
|
||||
DataGridRow,
|
||||
TableCell,
|
||||
TableCellActions,
|
||||
TableCellLayout,
|
||||
Button,
|
||||
Label,
|
||||
makeStyles,
|
||||
Title2,
|
||||
TableColumnDefinition,
|
||||
createTableColumn,
|
||||
} from "@fluentui/react-components";
|
||||
import { IHolidayItem } from "../../../../common/interfaces/HolidaysCalendar";
|
||||
import { Button, Label, makeStyles, Title2 } from "@fluentui/react-components";
|
||||
import { CalendarAdd20Regular, Diamond24Regular, ArrowDownload24Regular } from "@fluentui/react-icons";
|
||||
const useStyles = makeStyles({
|
||||
root: {
|
||||
marginTop: "25px",
|
||||
},
|
||||
root: {
|
||||
marginTop: "25px",
|
||||
},
|
||||
});
|
||||
|
||||
export default function HolidaysList(props: IHolidaysListProps) {
|
||||
const classes = useStyles();
|
||||
const [showOptionalIcon, setShowOptionalIcon] = React.useState<boolean>(false);
|
||||
export default function HolidaysList(props: IHolidaysListProps): JSX.Element {
|
||||
const classes = useStyles();
|
||||
const [showOptionalIcon, setShowOptionalIcon] = React.useState<boolean>(false);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (props.items.length > 0) {
|
||||
props.items.filter((item) => item.holidayType.optional).length > 0;
|
||||
setShowOptionalIcon(true);
|
||||
}
|
||||
}, [props.items]);
|
||||
const columns: ColumnDefinition<IHolidayItem>[] = React.useMemo(
|
||||
() => [
|
||||
createColumn<IHolidayItem>({
|
||||
columnId: "HolidayTitle",
|
||||
renderHeaderCell: () => {
|
||||
return "";
|
||||
},
|
||||
renderCell: (item) => {
|
||||
return (
|
||||
<TableCell>
|
||||
<TableCellLayout>{item.holidayTitle.label}</TableCellLayout>
|
||||
<TableCellActions>
|
||||
<Button icon={<CalendarAdd20Regular />} appearance="subtle" onClick={() => props.onCalendarAddClick(item.Id)} />
|
||||
</TableCellActions>
|
||||
</TableCell>
|
||||
);
|
||||
},
|
||||
}),
|
||||
createColumn<IHolidayItem>({
|
||||
columnId: "HolidayDate",
|
||||
renderHeaderCell: () => {
|
||||
return "";
|
||||
},
|
||||
renderCell: (item) => {
|
||||
return <TableCellLayout>{item.holidayDate.label}</TableCellLayout>;
|
||||
},
|
||||
}),
|
||||
createColumn<IHolidayItem>({
|
||||
columnId: "HolidayDay",
|
||||
renderHeaderCell: () => {
|
||||
return "";
|
||||
},
|
||||
renderCell: (item) => {
|
||||
return <TableCellLayout>{item.holidayDay.label}</TableCellLayout>;
|
||||
},
|
||||
}),
|
||||
createColumn<IHolidayItem>({
|
||||
columnId: "HolidayType",
|
||||
renderHeaderCell: () => {
|
||||
return "";
|
||||
},
|
||||
renderCell: (item) => {
|
||||
return (
|
||||
<TableCellLayout>
|
||||
{props.showFixedOptional ? (
|
||||
item.holidayType.optional ? (
|
||||
<Diamond24Regular primaryFill="Orange" />
|
||||
) : (
|
||||
<Diamond24Regular primaryFill="Green" />
|
||||
)
|
||||
) : null}
|
||||
</TableCellLayout>
|
||||
);
|
||||
},
|
||||
}),
|
||||
],
|
||||
[props.items, props.showFixedOptional]
|
||||
);
|
||||
React.useEffect(() => {
|
||||
if (props.items.length > 0) {
|
||||
if (props.items.filter((item) => item.holidayType.optional).length > 0) setShowOptionalIcon(true);
|
||||
}
|
||||
}, [props.items]);
|
||||
const columns: TableColumnDefinition<IHolidayItem>[] = React.useMemo(
|
||||
() => [
|
||||
createTableColumn<IHolidayItem>({
|
||||
columnId: "HolidayTitle",
|
||||
renderHeaderCell: () => {
|
||||
return "";
|
||||
},
|
||||
renderCell: (item: IHolidayItem) => {
|
||||
return (
|
||||
<TableCell>
|
||||
<TableCellLayout>{item.holidayTitle.label}</TableCellLayout>
|
||||
<TableCellActions>
|
||||
<Button icon={<CalendarAdd20Regular />} appearance="subtle" onClick={() => props.onCalendarAddClick(item.Id)} />
|
||||
</TableCellActions>
|
||||
</TableCell>
|
||||
);
|
||||
},
|
||||
}),
|
||||
createTableColumn<IHolidayItem>({
|
||||
columnId: "HolidayDate",
|
||||
renderHeaderCell: () => {
|
||||
return "";
|
||||
},
|
||||
renderCell: (item: IHolidayItem) => {
|
||||
return <TableCellLayout>{item.holidayDate.label}</TableCellLayout>;
|
||||
},
|
||||
}),
|
||||
createTableColumn<IHolidayItem>({
|
||||
columnId: "HolidayDay",
|
||||
renderHeaderCell: () => {
|
||||
return "";
|
||||
},
|
||||
renderCell: (item: IHolidayItem) => {
|
||||
return <TableCellLayout>{item.holidayDay.label}</TableCellLayout>;
|
||||
},
|
||||
}),
|
||||
createTableColumn<IHolidayItem>({
|
||||
columnId: "HolidayType",
|
||||
renderHeaderCell: () => {
|
||||
return "";
|
||||
},
|
||||
renderCell: (item: IHolidayItem) => {
|
||||
return (
|
||||
<TableCellLayout>
|
||||
{props.showFixedOptional ? (
|
||||
item.holidayType.optional ? (
|
||||
<Diamond24Regular primaryFill="Orange" />
|
||||
) : (
|
||||
<Diamond24Regular primaryFill="Green" />
|
||||
)
|
||||
) : null}
|
||||
</TableCellLayout>
|
||||
);
|
||||
},
|
||||
}),
|
||||
],
|
||||
[props.items, props.showFixedOptional]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Title2 align="center" style={{ fontFamily: "fontFamilyBase" }}>
|
||||
{props.title}
|
||||
</Title2>
|
||||
<DataGrid items={props.items} columns={columns} sortable={false} getRowId={(item: IHolidayItem) => item.Id}>
|
||||
<DataGridHeader>
|
||||
<DataGridRow>{({ renderHeaderCell }: ColumnDefinition<IHolidayItem>) => <DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>}</DataGridRow>
|
||||
</DataGridHeader>
|
||||
<DataGridBody>
|
||||
{({ item, rowId }: RowState<IHolidayItem>) => (
|
||||
<DataGridRow key={rowId}>{({ renderCell }: ColumnDefinition<IHolidayItem>) => <DataGridCell>{renderCell(item)}</DataGridCell>}</DataGridRow>
|
||||
)}
|
||||
</DataGridBody>
|
||||
</DataGrid>
|
||||
return (
|
||||
<>
|
||||
<Title2 align="center" style={{ fontFamily: "fontFamilyBase" }}>
|
||||
{props.title}
|
||||
</Title2>
|
||||
<DataGrid items={props.items} columns={columns} sortable={false} getRowId={(item: IHolidayItem) => item.Id}>
|
||||
<DataGridHeader>
|
||||
<DataGridRow>{({ renderHeaderCell }) => <DataGridHeaderCell>{renderHeaderCell()}</DataGridHeaderCell>}</DataGridRow>
|
||||
</DataGridHeader>
|
||||
<DataGridBody>
|
||||
{({ item, rowId }) => <DataGridRow key={rowId}>{({ renderCell }) => <DataGridCell>{renderCell(item)}</DataGridCell>}</DataGridRow>}
|
||||
</DataGridBody>
|
||||
</DataGrid>
|
||||
|
||||
{props.showDownload && (
|
||||
<Button icon={<ArrowDownload24Regular />} appearance="subtle" onClick={props.onDownloadItems} className={classes.root}>
|
||||
Download
|
||||
</Button>
|
||||
)}
|
||||
{props.showFixedOptional && (
|
||||
<div className={classes.root}>
|
||||
<Diamond24Regular primaryFill="Green" />
|
||||
<Label>Fixed Holiday</Label>
|
||||
{showOptionalIcon && (
|
||||
<>
|
||||
<Diamond24Regular primaryFill="Orange" />
|
||||
<Label>Optional/Flexible holiday</Label>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
{props.showDownload && (
|
||||
<Button icon={<ArrowDownload24Regular />} appearance="subtle" onClick={props.onDownloadItems} className={classes.root}>
|
||||
Download
|
||||
</Button>
|
||||
)}
|
||||
{props.showFixedOptional && (
|
||||
<div className={classes.root}>
|
||||
<Diamond24Regular primaryFill="Green" />
|
||||
<Label>Fixed Holiday</Label>
|
||||
{showOptionalIcon && (
|
||||
<>
|
||||
<Diamond24Regular primaryFill="Orange" />
|
||||
<Label>Optional/Flexible holiday</Label>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
import { ColumnDefinition } from "@fluentui/react-components/unstable";
|
||||
import { TableColumnDefinition } from "@fluentui/react-components";
|
||||
import { IHolidayItem, IHoliday } from "../../../common/interfaces/HolidaysCalendar";
|
||||
|
||||
export interface IEmployeeInfo {
|
||||
eMail: string;
|
||||
id: string;
|
||||
officeLocation: string;
|
||||
timezone: string;
|
||||
displayName: string;
|
||||
eMail: string;
|
||||
id: string;
|
||||
officeLocation: string;
|
||||
timezone: string;
|
||||
displayName: string;
|
||||
}
|
||||
export interface IHolidaysCalendarState {
|
||||
listItems: IHoliday[];
|
||||
holidayListItems: IHolidayItem[];
|
||||
message: {
|
||||
show: boolean;
|
||||
intent: "success" | "error";
|
||||
};
|
||||
employeeInfo: IEmployeeInfo;
|
||||
columns: ColumnDefinition<IHolidayItem>[];
|
||||
listItems: IHoliday[];
|
||||
holidayListItems: IHolidayItem[];
|
||||
message: {
|
||||
show: boolean;
|
||||
intent: "success" | "error";
|
||||
};
|
||||
employeeInfo: IEmployeeInfo;
|
||||
columns: TableColumnDefinition<IHolidayItem>[];
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"extends": "./node_modules/@microsoft/rush-stack-compiler-4.5/includes/tsconfig-web.json",
|
||||
"extends": "./node_modules/@microsoft/rush-stack-compiler-4.7/includes/tsconfig-web.json",
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue