| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,23 +1,44 @@ | ||
| { | ||
| "name": "countdown-widget", | ||
| "version": "1.0.0", | ||
| "description": "Microsoft DevLabs Countdown widget extension", | ||
| "keywords": [ | ||
| "vsts", | ||
| "tfs" | ||
| ], | ||
| "scripts": { | ||
| "build": "npm run lint && npm run clean && npm run webpack", | ||
| "clean": "rimraf ./dist && rimraf ./*.vsix", | ||
| "gallery-publish": "npm run build && tfx extension publish --rev-version --token mi244imrtmzyhxtiych23wf2e6titzfffbdhm25my5p3bob6el4q", | ||
| "lint": "tslint -c tslint.json 'src/*.ts'", | ||
| "package": "tfx extension create --rev-version", | ||
| "postbuild": "npm run package", | ||
| "webpack": "webpack --progress --colors --config webpack.config.js --output-path ./dist -p" | ||
| }, | ||
| "author": "ALM Rangers", | ||
| "license": "MIT", | ||
| "devDependencies": { | ||
| "cpx": "^1.5.0", | ||
| "rimraf": "^2.6.1", | ||
| "tfx-cli": "^0.4.5", | ||
| "ts-loader": "^2.0.0", | ||
| "tslint": "^5.2.0", | ||
| "tslint-loader": "^3.5.3", | ||
| "typescript": "2.3.2", | ||
| "webpack": "^2.5.1" | ||
| }, | ||
| "dependencies": { | ||
| "@types/jquery": "^2.0.34", | ||
| "@types/q": "0.0.32", | ||
| "@types/jasmine": "^2.5.53", | ||
| "applicationinsights-js": "^1.0.9", | ||
| "jasmine": "^2.4.1", | ||
| "jquery": "^3.1.0", | ||
| "moment": "^2.14.1", | ||
| "moment-timezone": "^0.5.4", | ||
| "requirejs": "^2.2.0", | ||
| "spectrum-colorpicker": "^1.8.0", | ||
| "telemetryclient-team-services-extension": "*", | ||
| "vss-web-extension-sdk": "^2.116.1" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| // --------------------------------------------------------------------- | ||
| // <copyright file="countdownResult.ts"> | ||
| // This code is licensed under the MIT License. | ||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
| // </copyright> | ||
| // <summary> | ||
| // This is part of the Countdown widget | ||
| // from the ALM Rangers. This file contains the | ||
| // code for a countdown result and unit. | ||
| // </summary> | ||
| // --------------------------------------------------------------------- | ||
|
|
||
| export class CountdownResult { | ||
|
|
||
| constructor(public value: number, public unit: Unit) { | ||
| } | ||
|
|
||
| public getDisplayString(): string { | ||
| return Unit[this.unit].toLowerCase(); | ||
| } | ||
| } | ||
|
|
||
| export enum Unit { Years, Days, Hours, Minutes, Seconds, Invalid } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,241 @@ | ||
| // --------------------------------------------------------------------- | ||
| // <copyright file="configuration.ts"> | ||
| // This code is licensed under the MIT License. | ||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
| // </copyright> | ||
| // <summary> | ||
| // This is part of the Countdown widget | ||
| // from the ALM Rangers. This file contains the | ||
| // widget configuration code. | ||
| // </summary> | ||
| // --------------------------------------------------------------------- | ||
|
|
||
| // tslint:disable-next-line | ||
| /// <reference path="isettings.d.ts" /> | ||
|
|
||
| import Work_Client = require("TFS/Work/RestClient"); | ||
| import Work_Contracts = require("TFS/Work/Contracts"); | ||
| import WebApi_Constants = require("VSS/WebApi/Constants"); | ||
| import TFS_Core_Contracts = require("TFS/Core/Contracts"); | ||
| import Service = require("VSS/Service"); | ||
| import Q = require("q"); | ||
| import Controls = require("VSS/Controls"); | ||
| import Combos = require("VSS/Controls/Combos"); | ||
| import moment = require("moment-timezone"); | ||
| import spectrum = require("spectrum-colorpicker"); | ||
|
|
||
| // import TelemetryClient = require("scripts/TelemetryClient"); | ||
|
|
||
| export class Configuration { | ||
| private static $dateTimeCombo: Combos.Combo = null; | ||
|
|
||
| private widgetConfigurationContext = null; | ||
| private $countdownDateInput = $("#countdown-date-input"); | ||
| private $datetimepicker = $("#datetimepicker") as any; | ||
| private $select = $("select"); | ||
| private $backgroundColor = $("#background-color-input"); | ||
| private $foregroundColor = $("#foreground-color-input"); | ||
| private $skipNonWorkingDays = $("#skipNonWorkingDays"); | ||
| private currentIterationEnd = null; | ||
| constructor(public WidgetHelpers, public isSprintWidget: boolean) { } | ||
|
|
||
| public load(widgetSettings, widgetConfigurationContext) { | ||
| this.widgetConfigurationContext = widgetConfigurationContext; | ||
|
|
||
| this.getCurrentIteration() | ||
| .then((currentIterationEnd) => { | ||
| this.currentIterationEnd = currentIterationEnd; | ||
| const settings: ISettings = JSON.parse(widgetSettings.customSettings.data); | ||
|
|
||
| this.showTimezones(settings); | ||
| this.showColorPickers(settings); | ||
| this.showDateTimePicker(settings, currentIterationEnd); | ||
| this.showWorkingDays(settings); | ||
|
|
||
| VSS.resize(); | ||
| this.$select | ||
| .add(this.$backgroundColor) | ||
| .add(this.$foregroundColor) | ||
| .add(this.$skipNonWorkingDays) | ||
| .change(() => { | ||
| this.widgetConfigurationContext.notify(this.WidgetHelpers.WidgetEvent.ConfigurationChange, | ||
| this.WidgetHelpers.WidgetEvent.Args(this.getCustomSettings())); | ||
| }); | ||
| }); | ||
|
|
||
| return this.WidgetHelpers.WidgetStatusHelper.Success(); | ||
| } | ||
|
|
||
| public onSave() { | ||
| const isValid = true; | ||
| if (isValid) { | ||
| // TelemetryClient.TelemetryClient.getClient().trackEvent("Updated configuration"); | ||
| return this.WidgetHelpers.WidgetConfigurationSave.Valid(this.getCustomSettings()); | ||
| } else { | ||
| return this.WidgetHelpers.WidgetConfigurationSave.Invalid(); | ||
| } | ||
|
|
||
| } | ||
|
|
||
| private showDateTimePicker(settings, currentIterationEnd) { | ||
| if (!this.isSprintWidget) { | ||
| let countDownDate = moment().format("MM-DD-YYYY HH:mm"); | ||
| if (settings && settings.countDownDate) { | ||
| countDownDate = settings.countDownDate; | ||
| } else { | ||
| countDownDate = moment().add(1, "days").format("MM-DD-YYYY HH:mm"); | ||
| } | ||
|
|
||
| const dateTimeOptions: Combos.IDateTimeComboOptions = { | ||
| change: () => { | ||
| this.widgetConfigurationContext.notify(this.WidgetHelpers.WidgetEvent.ConfigurationChange, | ||
| this.WidgetHelpers.WidgetEvent.Args(this.getCustomSettings())); | ||
| }, | ||
| dateTimeFormat: "F", | ||
| type: "date-time", | ||
| value: countDownDate, | ||
| }; | ||
| Configuration.$dateTimeCombo = Controls.create(Combos.Combo, this.$datetimepicker, dateTimeOptions); | ||
| } else { | ||
| this.$datetimepicker.hide(); | ||
| $(".countdown-config-label").hide(); | ||
| } | ||
| } | ||
|
|
||
| private showColorPickers(settings) { | ||
| const palette = [ | ||
| ["black", "white", "tan", "turquoise", "pink"], | ||
| ["red", "yellow", "green", "blue", "violet"], | ||
| ]; | ||
|
|
||
| const colorSettings = { | ||
| color: "", | ||
| hideAfterPaletteSelect: true, | ||
| palette, | ||
| showPalette: true, | ||
| showPaletteOnly: true, | ||
| }; | ||
|
|
||
| colorSettings.color = (settings && settings.backgroundColor) ? | ||
| settings.backgroundColor | ||
| : "green"; | ||
|
|
||
| (this.$backgroundColor as any).spectrum(colorSettings); | ||
|
|
||
| colorSettings.color = (settings && settings.foregroundColor) ? | ||
| settings.foregroundColor | ||
| : "white"; | ||
| (this.$foregroundColor as any).spectrum(colorSettings); | ||
|
|
||
| } | ||
|
|
||
| private showTimezones(settings) { | ||
| if (!this.isSprintWidget) { | ||
| const timezones = moment.tz.names(); | ||
| for (let i = 0; i < timezones.length; i++) { | ||
| const opt = document.createElement("option"); | ||
| opt.innerHTML = timezones[i]; | ||
| opt.value = timezones[i]; | ||
| this.$select[0].appendChild(opt); | ||
| } | ||
|
|
||
| if (settings && settings.timezone) { | ||
| this.$select.val(settings.timezone); | ||
| } else { | ||
| this.$select.val((moment as any).tz.guess()); | ||
| } | ||
| } else { | ||
| this.$select.hide(); | ||
| $(".countdown-config-label").hide(); | ||
| } | ||
| } | ||
|
|
||
| private showWorkingDays(settings) { | ||
| if (settings) { | ||
| this.$skipNonWorkingDays.prop("checked", settings.skipNonWorkingDays); | ||
| } else { | ||
| this.$skipNonWorkingDays.prop("checked", false); | ||
| } | ||
| } | ||
|
|
||
| private getCustomSettings() { | ||
| let formattedDate = ""; | ||
| if (this.isSprintWidget) { | ||
| if (this.currentIterationEnd) { | ||
| formattedDate = moment(this.currentIterationEnd).format("MM-DD-YYYY HH:mm"); | ||
| } | ||
| } else { | ||
| const selectedDate = Configuration.$dateTimeCombo.getInputText(); | ||
| if (selectedDate) { | ||
| formattedDate = moment(selectedDate).format("MM-DD-YYYY HH:mm"); | ||
| } | ||
| } | ||
|
|
||
| const foregroundColor = (this.$foregroundColor as any).spectrum("get").toRgbString(); | ||
| const backgroundColor = (this.$backgroundColor as any).spectrum("get").toRgbString(); | ||
| const skipNonWorkingDays = this.$skipNonWorkingDays.prop("checked"); | ||
|
|
||
| const result = { | ||
| data: JSON.stringify({ | ||
| backgroundColor, | ||
| countDownDate: formattedDate, | ||
| foregroundColor, | ||
| skipNonWorkingDays, | ||
| timezone: $("select").val(), | ||
| } as ISettings), | ||
| }; | ||
| return result; | ||
| } | ||
|
|
||
| private getCurrentIteration(): IPromise<Date> { | ||
| const deferred = Q.defer<Date>(); | ||
| const webContext = VSS.getWebContext(); | ||
| const teamContext: TFS_Core_Contracts.TeamContext = { | ||
| project: "", | ||
| projectId: webContext.project.id, | ||
| team: "", | ||
| teamId: webContext.team.id, | ||
| }; | ||
|
|
||
| const workClient: Work_Client.WorkHttpClient = Service.VssConnection | ||
| .getConnection() | ||
| .getHttpClient(Work_Client.WorkHttpClient, WebApi_Constants.ServiceInstanceTypes.TFS); | ||
|
|
||
| workClient.getTeamIterations(teamContext).then((iterations) => { | ||
| if (iterations.length > 0) { | ||
| workClient.getTeamIterations(teamContext, "current").then((teamIterations) => { | ||
| if (teamIterations.length > 0) { | ||
| deferred.resolve(teamIterations[0].attributes.finishDate); | ||
| } else { | ||
| deferred.resolve(null); | ||
| } | ||
| }); | ||
| } else { | ||
| deferred.resolve(null); | ||
| } | ||
| }); | ||
|
|
||
| return deferred.promise; | ||
| } | ||
| } | ||
|
|
||
| VSS.require(["TFS/Dashboards/WidgetHelpers"], (WidgetHelpers) => { | ||
| VSS.register("SprintEndCountdownWidget-Configuration", () => { | ||
| const configuration = new Configuration(WidgetHelpers, true); | ||
| return configuration; | ||
| }); | ||
|
|
||
| VSS.notifyLoadSucceeded(); | ||
| }); | ||
|
|
||
| VSS.require(["TFS/Dashboards/WidgetHelpers"], (WidgetHelpers) => { | ||
| VSS.register("CountdownWidget-Configuration", () => { | ||
| const configuration = new Configuration(WidgetHelpers, false); | ||
| return configuration; | ||
| }); | ||
|
|
||
| VSS.notifyLoadSucceeded(); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,110 @@ | ||
| // --------------------------------------------------------------------- | ||
| // <copyright file="countdownCalculator.ts"> | ||
| // This code is licensed under the MIT License. | ||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
| // </copyright> | ||
| // <summary> | ||
| // This is part of the Countdown widget | ||
| // from the ALM Rangers. This file contains the | ||
| // code to calculate the countdown delta. | ||
| // </summary> | ||
| // --------------------------------------------------------------------- | ||
|
|
||
| import moment = require("moment-timezone"); | ||
| import countdownResult = require("./CountdownResult"); | ||
|
|
||
| export class CountdownCalculator { | ||
|
|
||
| private from: moment.Moment; | ||
| private to: moment.Moment; | ||
| private workingdays: string[]; | ||
|
|
||
| constructor(from: moment.Moment, to: moment.Moment, workingdays: string[] = []) { | ||
| this.from = from; | ||
| this.to = to; | ||
| this.workingdays = workingdays; | ||
| } | ||
|
|
||
| public getDifference(): countdownResult.CountdownResult { | ||
| if (!this.isValid()) { | ||
| return new countdownResult.CountdownResult(0, countdownResult.Unit.Invalid); | ||
| } | ||
|
|
||
| const diff = (unit: countdownResult.Unit) => { | ||
| return this.to.diff(this.from, countdownResult.Unit[unit].toLowerCase(), false); | ||
| }; | ||
|
|
||
| let numberOfExcludedDays = 0; | ||
| if (this.workingdays.length > 0) { | ||
| numberOfExcludedDays = this.countExcluded(); | ||
| } | ||
|
|
||
| const test = diff(countdownResult.Unit.Days); | ||
| this.to.add(-numberOfExcludedDays, countdownResult.Unit[countdownResult.Unit.Days].toLowerCase()); | ||
| const numberOfDays = diff(countdownResult.Unit.Days); | ||
|
|
||
| if (numberOfDays >= 1) { | ||
| return new countdownResult.CountdownResult(numberOfDays, countdownResult.Unit.Days); | ||
| } else { | ||
| const numberOfHours = diff(countdownResult.Unit.Hours); | ||
|
|
||
| if (numberOfHours >= 1) { | ||
| return new countdownResult.CountdownResult(numberOfHours, countdownResult.Unit.Hours); | ||
| } else { | ||
| const numberOfMinutes = diff(countdownResult.Unit.Minutes); | ||
| if (numberOfMinutes >= 1) { | ||
| return new countdownResult.CountdownResult(numberOfMinutes, countdownResult.Unit.Minutes); | ||
| } else { | ||
| const numberOfSeconds = diff(countdownResult.Unit.Seconds); | ||
| return new countdownResult.CountdownResult(numberOfSeconds, countdownResult.Unit.Seconds); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public isValid(): boolean { | ||
| return this.from.isBefore(this.to.format()); | ||
| } | ||
|
|
||
| private getDayOfWeekNumber(day: any): number { | ||
| if (typeof day === "string") { // for compatibility with old API | ||
| switch (day) { | ||
| case "sunday": return 0; | ||
| case "monday": return 1; | ||
| case "tuesday": return 2; | ||
| case "wednesday": return 3; | ||
| case "thursday": return 4; | ||
| case "friday": return 5; | ||
| case "saturday": return 6; | ||
| } | ||
| } else { | ||
| return day; | ||
| } | ||
|
|
||
| } | ||
|
|
||
| private isWorkDay(day: number): boolean { | ||
| for (const dayString of this.workingdays) { | ||
| const workingDay = this.getDayOfWeekNumber(dayString); | ||
| if (workingDay === day) { | ||
| return true; | ||
| } | ||
| } | ||
| return false; | ||
| } | ||
|
|
||
| private countExcluded(): number { | ||
| const days = this.to.diff(this.from, "days"); | ||
| let excludedDays = 0; | ||
| for (let i = 1; i <= days; i++) { // starting from 1 for not include the current day | ||
| const weekday = this.from.clone().add(i, "days").weekday(); | ||
| if (!this.isWorkDay(weekday)) { | ||
| excludedDays++; | ||
| } | ||
| } | ||
| return excludedDays; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,198 @@ | ||
| // --------------------------------------------------------------------- | ||
| // <copyright file="countdownWidget.ts"> | ||
| // This code is licensed under the MIT License. | ||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
| // </copyright> | ||
| // <summary> | ||
| // This is part of the Countdown widget | ||
| // from the ALM Rangers. This file contains the | ||
| // main code for the widget. | ||
| // </summary> | ||
| // --------------------------------------------------------------------- | ||
|
|
||
| import CountdownCalculator = require("./countdownCalculator"); | ||
| import moment = require("moment-timezone"); | ||
| import Work_Client = require("TFS/Work/RestClient"); | ||
| import Work_Contracts = require("TFS/Work/Contracts"); | ||
| import WebApi_Constants = require("VSS/WebApi/Constants"); | ||
| import TFS_Core_Contracts = require("TFS/Core/Contracts"); | ||
| import Service = require("VSS/Service"); | ||
| import Q = require("q"); | ||
| import System_Contracts = require("VSS/Common/Contracts/System"); | ||
|
|
||
| export class CountdownWiget { | ||
| constructor( | ||
| public WidgetHelpers, | ||
| public isSprintEndWidget: boolean) { } | ||
|
|
||
| public load(widgetSettings) { | ||
| return this.showCountdown(widgetSettings); | ||
| } | ||
|
|
||
| public reload(widgetSettings) { | ||
| return this.showCountdown(widgetSettings); | ||
| } | ||
|
|
||
| private showSprintWidget(customSettings: ISettings, workingdays: System_Contracts.DayOfWeek[]) { | ||
| const webContext = VSS.getWebContext(); | ||
| const teamContext: TFS_Core_Contracts.TeamContext = { | ||
| project: "", | ||
| projectId: webContext.project.id, | ||
| team: "", | ||
| teamId: webContext.team.id, | ||
| }; | ||
| const workClient: Work_Client.WorkHttpClient = Service.VssConnection | ||
| .getConnection() | ||
| .getHttpClient(Work_Client.WorkHttpClient, WebApi_Constants.ServiceInstanceTypes.TFS); | ||
|
|
||
| return workClient.getTeamIterations(teamContext).then((iterations) => { | ||
| if (iterations.length > 0) { | ||
| return workClient.getTeamIterations(teamContext, "current").then((teamIterations) => { | ||
|
|
||
| const iterationEndDate = teamIterations[0].attributes.finishDate; | ||
| if (iterationEndDate) { | ||
| let iterationLastDay: moment.Moment; | ||
| iterationLastDay = moment.utc(iterationEndDate).hour(23).minute(59).second(59); | ||
| // convert to utc else is convert to local time zone date | ||
| // .hour(23).minute(59).second(59) for have full last day iteration | ||
| return this.display( | ||
| iterationLastDay, | ||
| customSettings.name, | ||
| customSettings.backgroundColor, | ||
| customSettings.foregroundColor, | ||
| workingdays); | ||
| } else { | ||
| return this.display( | ||
| null, | ||
| customSettings.name, | ||
| customSettings.backgroundColor, | ||
| customSettings.foregroundColor, | ||
| workingdays); | ||
| } | ||
| }); | ||
| } else { | ||
| return this.display( | ||
| null, | ||
| customSettings.name, | ||
| customSettings.backgroundColor, | ||
| customSettings.foregroundColor, | ||
| workingdays); | ||
| } | ||
| }); | ||
| } | ||
|
|
||
| private display(to, name: string, backgroundColor, foregroundColor, workingdays: System_Contracts.DayOfWeek[]) { | ||
| const $title = $(".title"); | ||
| const $container = $("#countdown-container"); | ||
| const $countdownBottomContainer = $("#countdown-bottom-container"); | ||
| const $errorContainer = $("#error-container"); | ||
| const $countDownBody = $(".countdown"); | ||
|
|
||
| $title.text(name); | ||
|
|
||
| if (backgroundColor) { | ||
| $countDownBody.css("background-color", backgroundColor); | ||
| } | ||
| if (foregroundColor) { | ||
| $countDownBody.css("color", foregroundColor); | ||
| } | ||
|
|
||
| if (!to) { | ||
| $errorContainer.text("Sorry, nothing to show"); | ||
| $title | ||
| .add($container) | ||
| .add($countdownBottomContainer) | ||
| .hide(); | ||
| return this.WidgetHelpers.WidgetStatusHelper.Success(); | ||
| } else { | ||
| $title. | ||
| add($container) | ||
| .add($countdownBottomContainer) | ||
| .show(); | ||
| $errorContainer.empty(); | ||
| } | ||
|
|
||
| const now = moment(); | ||
| const tempWorkingDays = []; | ||
|
|
||
| workingdays.forEach((element) => { | ||
| tempWorkingDays.push(element); | ||
| }); | ||
|
|
||
| const calculator = new CountdownCalculator.CountdownCalculator( | ||
| now, | ||
| to, | ||
| tempWorkingDays, | ||
| ); | ||
|
|
||
| if (calculator.isValid()) { | ||
| const result = calculator.getDifference(); | ||
| $container.text(result.value); | ||
| $countdownBottomContainer.text(result.getDisplayString() + " remaining"); | ||
| } else { | ||
| $container.text(0); | ||
| $countdownBottomContainer.text("days remaining"); | ||
| } | ||
|
|
||
| return this.WidgetHelpers.WidgetStatusHelper.Success(); | ||
| } | ||
|
|
||
| private showCountdownWidget(customSettings, workingdays) { | ||
| return this.display( | ||
| moment.tz(customSettings.countDownDate, "MM-DD-YYYY HH:mm", customSettings.timezone), | ||
| customSettings.name, | ||
| customSettings.backgroundColor, | ||
| customSettings.foregroundColor, | ||
| workingdays); | ||
| } | ||
|
|
||
| private showCountdown(widgetSettings) { | ||
| let customSettings = JSON.parse(widgetSettings.customSettings.data) as ISettings; | ||
|
|
||
| if (!customSettings) { | ||
| customSettings = { | ||
| backgroundColor: "green", | ||
| countDownDate: moment().add(1, "days").format("MM-DD-YYYY HH:mm"), | ||
| foregroundColor: "white", | ||
| name: widgetSettings.name, | ||
| skipNonWorkingDays: false, | ||
| timezone: (moment as any).tz.guess(), | ||
| }; | ||
| } else { | ||
| customSettings.name = widgetSettings.name; | ||
| } | ||
|
|
||
| try { | ||
| const webContext = VSS.getWebContext(); | ||
| const teamContext: TFS_Core_Contracts.TeamContext = { | ||
| project: "", | ||
| projectId: webContext.project.id, | ||
| team: "", | ||
| teamId: webContext.team.id, | ||
| }; | ||
|
|
||
| const workClient: Work_Client.WorkHttpClient = Service.VssConnection | ||
| .getConnection() | ||
| .getHttpClient(Work_Client.WorkHttpClient, WebApi_Constants.ServiceInstanceTypes.TFS); | ||
|
|
||
| return workClient.getTeamSettings(teamContext).then((teamSettings) => { | ||
|
|
||
| let workingdays: System_Contracts.DayOfWeek[] = []; | ||
| if (customSettings.skipNonWorkingDays) { | ||
| workingdays = teamSettings.workingDays; | ||
| } | ||
|
|
||
| if (this.isSprintEndWidget) { | ||
| return this.showSprintWidget(customSettings, workingdays); | ||
| } else { | ||
| return this.showCountdownWidget(customSettings, workingdays); | ||
| } | ||
| }); | ||
| } catch (e) { | ||
| // telemetry.log(..) | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,23 @@ | ||
| // --------------------------------------------------------------------- | ||
| // <copyright file="isettings.d.ts"> | ||
| // This code is licensed under the MIT License. | ||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
| // </copyright> | ||
| // <summary> | ||
| // This is part of the Countdown widget | ||
| // from the ALM Rangers. This file contains the | ||
| // typescript definition for the widget settings. | ||
| // </summary> | ||
| // --------------------------------------------------------------------- | ||
|
|
||
| interface ISettings { | ||
| countDownDate: string; | ||
| timezone: string; | ||
| name: string; | ||
| backgroundColor: string; | ||
| foregroundColor: string; | ||
| skipNonWorkingDays: boolean; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,38 @@ | ||
| // --------------------------------------------------------------------- | ||
| // <copyright file="main.ts"> | ||
| // This code is licensed under the MIT License. | ||
| // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF | ||
| // ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED | ||
| // TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A | ||
| // PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
| // </copyright> | ||
| // <summary> | ||
| // This is part of the Countdown widget | ||
| // from the ALM Rangers. This file contains the | ||
| // widget startup code. | ||
| // </summary> | ||
| // --------------------------------------------------------------------- | ||
|
|
||
| // tslint:disable-next-line | ||
| /// <reference path="isettings.d.ts"/> | ||
|
|
||
| import CountdownWidget = require("./countdownWidget"); | ||
| // import TelemetryClient = require("scripts/TelemetryClient"); | ||
|
|
||
| VSS.require(["TFS/Dashboards/WidgetHelpers"], (WidgetHelpers) => { | ||
| VSS.register("SprintEndCountdownWidget", () => { | ||
| const countdownWidget = new CountdownWidget.CountdownWiget(WidgetHelpers, true); | ||
| // TelemetryClient.TelemetryClient.getClient().trackEvent("SprintEndCountdownWidget created"); | ||
| return countdownWidget; | ||
| }); | ||
| VSS.notifyLoadSucceeded(); | ||
| }); | ||
|
|
||
| VSS.require(["TFS/Dashboards/WidgetHelpers"], (WidgetHelpers) => { | ||
| VSS.register("CountdownWidget", () => { | ||
| const countdownWidget = new CountdownWidget.CountdownWiget(WidgetHelpers, false); | ||
| // TelemetryClient.TelemetryClient.getClient().trackEvent("CountdownWidget created"); | ||
| return countdownWidget; | ||
| }); | ||
| VSS.notifyLoadSucceeded(); | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import * as tc from "telemetryclient-team-services-extension"; | ||
|
|
||
| export const settings: tc.TelemetryClientSettings = { | ||
| disableAjaxTracking: "false", | ||
| disableTelemetry: "false", | ||
| enableDebug: "false", | ||
| extensioncontext: "CountdownWidget", | ||
| key: "__InstrumentationKey__", | ||
| }; |