From 461c26f976d9221845b6fcdbda22288483292488 Mon Sep 17 00:00:00 2001 From: Alexey Rodionov Date: Mon, 26 Jun 2017 12:46:22 -0700 Subject: [PATCH 01/21] Key and URL on Get Function URL tooltip do not match.Fixes #1489 --- .../src/app/function-dev/function-dev.component.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/AzureFunctions.AngularClient/src/app/function-dev/function-dev.component.ts b/AzureFunctions.AngularClient/src/app/function-dev/function-dev.component.ts index 2775f9f2d8..198d7a7664 100644 --- a/AzureFunctions.AngularClient/src/app/function-dev/function-dev.component.ts +++ b/AzureFunctions.AngularClient/src/app/function-dev/function-dev.component.ts @@ -612,7 +612,12 @@ export class FunctionDevComponent implements OnChanges, OnDestroy { } setShowFunctionInvokeUrlModal(value: boolean) { + var allKeys = this.functionKeys.keys.concat(this.hostKeys.keys); + if (allKeys) { + this.onChangeKey(allKeys[0].value); + } this.showFunctionInvokeUrlModal = value; + } setShowFunctionKeyModal(value: boolean) { From e9b66794139e6cf4a65f575da39e24cfde83e4d0 Mon Sep 17 00:00:00 2001 From: Alexey Rodionov Date: Tue, 27 Jun 2017 14:34:42 -0700 Subject: [PATCH 02/21] WebHooks UI needs to account for clientid requirement. Fixes #1490 --- .../function-dev/function-dev.component.html | 5 +-- .../function-dev/function-dev.component.ts | 40 ++++++++++++++----- .../src/app/shared/models/portal-resources.ts | 2 +- .../ResourcesPortal/Resources.Designer.cs | 9 ----- AzureFunctions/ResourcesPortal/Resources.resx | 3 -- 5 files changed, 34 insertions(+), 25 deletions(-) diff --git a/AzureFunctions.AngularClient/src/app/function-dev/function-dev.component.html b/AzureFunctions.AngularClient/src/app/function-dev/function-dev.component.html index 32779108ea..6693776a18 100644 --- a/AzureFunctions.AngularClient/src/app/function-dev/function-dev.component.html +++ b/AzureFunctions.AngularClient/src/app/function-dev/function-dev.component.html @@ -6,7 +6,7 @@ {{'keysDialog_getFunctionUrl' | translate}} \ No newline at end of file + + +
+
+
+ + Function runtime settings + API definition +
+ + +
+
diff --git a/AzureFunctions.AngularClient/src/app/site/site-manage/site-manage.component.scss b/AzureFunctions.AngularClient/src/app/site/site-manage/site-manage.component.scss index 20d5bf0616..5ef7ef0936 100644 --- a/AzureFunctions.AngularClient/src/app/site/site-manage/site-manage.component.scss +++ b/AzureFunctions.AngularClient/src/app/site/site-manage/site-manage.component.scss @@ -34,4 +34,16 @@ .site-manage-feature-group{ margin: 25px 0px 30px 0px; +} + +#back-bar{ + background-color: $back-bar-color; + height: 40px; + font-size: 18px; + padding: 7px; + + i{ + margin-left: 15px; + margin-right: 5px; + } } \ No newline at end of file diff --git a/AzureFunctions.AngularClient/src/app/site/site-manage/site-manage.component.ts b/AzureFunctions.AngularClient/src/app/site/site-manage/site-manage.component.ts index 0cf079620b..8e44cb6a13 100644 --- a/AzureFunctions.AngularClient/src/app/site/site-manage/site-manage.component.ts +++ b/AzureFunctions.AngularClient/src/app/site/site-manage/site-manage.component.ts @@ -1,3 +1,7 @@ +import { Subscription as RxSubscription } from 'rxjs/Subscription'; +import { SiteDashboardComponent } from './../site-dashboard/site-dashboard.component'; +import { Url } from './../../shared/Utilities/url'; +import { SiteTabIds } from './../../shared/models/constants'; import {Component, OnInit, EventEmitter, Input, Output} from '@angular/core'; import { Observable } from 'rxjs/Observable'; import { Subject } from 'rxjs/Subject'; @@ -6,14 +10,13 @@ import 'rxjs/add/operator/retry'; import 'rxjs/add/operator/switchMap'; import 'rxjs/add/observable/zip'; import { TranslateService } from '@ngx-translate/core'; - import { PortalResources } from './../../shared/models/portal-resources'; import { GlobalStateService } from './../../shared/services/global-state.service'; import { CacheService } from './../../shared/services/cache.service'; import { TreeViewInfo } from './../../tree-view/models/tree-view-info'; import { AiService } from './../../shared/services/ai.service'; import { Message } from './../../shared/models/portal'; -import { DisableableBladeFeature, DisableableFeature, DisableInfo } from './../../feature-group/feature-item'; +import { DisableableBladeFeature, DisableableFeature, DisableInfo, TabFeature, FeatureItem, BladeFeature, OpenBrowserWindowFeature} from './../../feature-group/feature-item'; import { FeatureGroup } from './../../feature-group/feature-group'; import {ArmService} from '../../shared/services/arm.service'; import {AuthzService} from '../../shared/services/authz.service'; @@ -23,7 +26,6 @@ import {ArmObj} from '../../shared/models/arm/arm-obj'; import {SiteDescriptor} from '../../shared/resourceDescriptors'; import {PopOverComponent} from '../../pop-over/pop-over.component'; import {FeatureGroupComponent} from '../../feature-group/feature-group.component'; -import {FeatureItem, TabFeature, BladeFeature, OpenBrowserWindowFeature} from '../../feature-group/feature-item'; import {WebsiteId} from '../../shared/models/portal'; @Component({ @@ -39,16 +41,23 @@ export class SiteManageComponent { public groups3 : FeatureGroup[]; public searchTerm = ""; + public TabIds = SiteTabIds; + + public viewInfo : TreeViewInfo; + + // Used to open features within the same tab instead of in a new tab + public selectedFeatureId : string | null = null; + private _viewInfoStream = new Subject(); - private _viewInfo : TreeViewInfo; private _descriptor : SiteDescriptor; private _hasSiteWritePermissionStream = new Subject(); private _hasPlanReadPermissionStream = new Subject(); private _dynamicDisableInfo : DisableInfo; + private _tabsFeature: string; - @Output() openTabEvent = new Subject(); + private _selectedFeatureSubscription : RxSubscription; set viewInfoInput(viewInfo : TreeViewInfo){ this._viewInfoStream.next(viewInfo); @@ -60,17 +69,20 @@ export class SiteManageComponent { private _aiService : AiService, private _cacheService : CacheService, private _globalStateService : GlobalStateService, - private _translateService : TranslateService){ + private _translateService : TranslateService, + private _siteDashboard : SiteDashboardComponent){ + + this._tabsFeature = Url.getParameterByName(window.location.href, "appsvc.feature.tabs"); this._viewInfoStream .switchMap(viewInfo =>{ - this._viewInfo = viewInfo; + this.viewInfo = viewInfo; this._globalStateService.setBusyState(); return this._cacheService.getArm(viewInfo.resourceId); }) .switchMap(r =>{ this._globalStateService.clearBusyState(); - let traceKey = this._viewInfo.data.siteTraceKey; + let traceKey = this.viewInfo.data.siteTraceKey; this._aiService.stopTrace("/site/features-tab-ready", traceKey); let site : ArmObj = r.json(); @@ -122,11 +134,21 @@ export class SiteManageComponent { disableMessage : this._translateService.instant(PortalResources.featureDisabledNoPermissionToPlan) }) }); + + this._selectedFeatureSubscription = this._siteDashboard.openFeatureId.subscribe(featureId => { + if(this._tabsFeature === "inplace"){ + this.selectedFeatureId = featureId; + } + }) } ngOnDestroy() { this._portalService.closeBlades(); this._disposeGroups(); + if(this._selectedFeatureSubscription){ + this._selectedFeatureSubscription.unsubscribe(); + this._selectedFeatureSubscription = null; + } } private _disposeGroups(){ @@ -227,7 +249,8 @@ export class SiteManageComponent { this._dynamicDisableInfo), ] - let generalFeatures = [ + let generalFeatures: FeatureItem[] = [ + new BladeFeature( this._translateService.instant(PortalResources.feature_applicationSettingsName), this._translateService.instant(PortalResources.feature_applicationSettingsName) + @@ -287,6 +310,18 @@ export class SiteManageComponent { this._portalService) ] + if(this._tabsFeature === 'tabs' || this._tabsFeature === 'inplace'){ + generalFeatures.splice(0, 0, + new TabFeature( + this._translateService.instant(PortalResources.tab_functionSettings), + this._translateService.instant(PortalResources.tab_functionSettings), + this._translateService.instant(PortalResources.feature_functionSettingsInfo), + "images/functions.svg", + SiteTabIds.functionRuntime, + this._siteDashboard) + ); + } + this.groups1 = [ new FeatureGroup(this._translateService.instant(PortalResources.feature_generalSettings), generalFeatures), new FeatureGroup(this._translateService.instant(PortalResources.feature_codeDeployment), codeDeployFeatures), @@ -422,7 +457,7 @@ export class SiteManageComponent { } private _initCol3Groups(site : ArmObj){ - let apiManagementFeatures = [ + let apiManagementFeatures: FeatureItem[] = [ new BladeFeature( "CORS", "cors api", @@ -432,19 +467,20 @@ export class SiteManageComponent { detailBlade : "ApiCors", detailBladeInputs : { resourceUri : site.id } }, - this._portalService), + this._portalService) + ] - new BladeFeature( + if(this._tabsFeature === "tabs" || this._tabsFeature === "inplace"){ + apiManagementFeatures.splice(0, 0, + new TabFeature( this._translateService.instant(PortalResources.feature_apiDefinitionName), this._translateService.instant(PortalResources.feature_apiDefinitionName) + " swagger", this._translateService.instant(PortalResources.feature_apiDefinitionInfo), "images/api-definition.svg", - { - detailBlade : "ApiDefinition", - detailBladeInputs : { resourceUri : site.id } - }, - this._portalService), - ] + SiteTabIds.apiDefinition, + this._siteDashboard + )); + } let appServicePlanFeatures = [ new DisableableBladeFeature( @@ -574,8 +610,9 @@ export class SiteManageComponent { new FeatureGroup(this._translateService.instant(PortalResources.feature_resourceManagement), resourceManagementFeatures)]; } - openTab(tabName : string){ - this.openTabEvent.next(tabName); + navBack(){ + // this.selectedFeatureId = null; + this._siteDashboard.openFeature(null); } } diff --git a/AzureFunctions.AngularClient/src/app/site/site-summary/site-summary.component.html b/AzureFunctions.AngularClient/src/app/site/site-summary/site-summary.component.html index dc2b0cf835..29a33d139d 100644 --- a/AzureFunctions.AngularClient/src/app/site/site-summary/site-summary.component.html +++ b/AzureFunctions.AngularClient/src/app/site/site-summary/site-summary.component.html @@ -104,7 +104,7 @@

{{ 'enabledFeatures_header' | translate }}

- +
diff --git a/AzureFunctions.AngularClient/src/app/site/site-summary/site-summary.component.ts b/AzureFunctions.AngularClient/src/app/site/site-summary/site-summary.component.ts index a5f657efad..5a4f7cfe2f 100644 --- a/AzureFunctions.AngularClient/src/app/site/site-summary/site-summary.component.ts +++ b/AzureFunctions.AngularClient/src/app/site/site-summary/site-summary.component.ts @@ -1,3 +1,5 @@ +import { TabsComponent } from './../../tabs/tabs.component'; +import { BusyStateComponent } from './../../busy-state/busy-state.component'; import { UserService } from './../../shared/services/user.service'; import { Component, OnInit, EventEmitter, Input, Output, OnDestroy } from '@angular/core'; import { Response } from '@angular/http'; @@ -80,13 +82,12 @@ export class SiteSummaryComponent implements OnDestroy { public Resources = PortalResources; public showDownloadFunctionAppModal = false; - @Output() openTabEvent = new Subject(); - private _viewInfoStream: Subject; private _viewInfo: TreeViewInfo; private _subs: Subscription[]; private _blobUrl: string; private _isSlot: boolean; + private _busyState : BusyStateComponent; constructor( private _cacheService: CacheService, @@ -99,9 +100,11 @@ export class SiteSummaryComponent implements OnDestroy { public ts: TranslateService, private _configService: ConfigService, private _slotService: SlotsService, - userService: UserService) { + userService: UserService, + tabsComponent : TabsComponent) { this.isStandalone = _configService.isStandalone(); + this._busyState = tabsComponent.busyState; userService.getStartupInfo() .first() @@ -114,7 +117,7 @@ export class SiteSummaryComponent implements OnDestroy { .switchMap(viewInfo => { this._viewInfo = viewInfo; - this._globalStateService.setBusyState(); + this._busyState.setBusyState(); return this._cacheService.getArm(viewInfo.resourceId); }) .mergeMap(r => { @@ -158,7 +161,7 @@ export class SiteSummaryComponent implements OnDestroy { let resourceId = site.id.substring(0, site.id.indexOf("/slots")); availabilityId = `${resourceId}/providers/Microsoft.ResourceHealth/availabilityStatuses/current`; } - this._globalStateService.clearBusyState(); + this._busyState.clearBusyState(); let traceKey = this._viewInfo.data.siteTraceKey; this._aiService.stopTrace("/site/overview-tab-ready", traceKey); this.hideAvailability = this._isSlot || site.properties.sku === "Dynamic"; @@ -212,7 +215,7 @@ export class SiteSummaryComponent implements OnDestroy { return Observable.of(res); }) .do(null, e => { - this._globalStateService.clearBusyState(); + this._busyState.clearBusyState(); if (!this._globalStateService.showTryView) { this._aiService.trackException(e, "site-summary"); @@ -255,10 +258,6 @@ export class SiteSummaryComponent implements OnDestroy { this._cleanupBlob(); } - openComponent(component: string) { - this.openTabEvent.next(component); - } - toggleState() { if (!this.hasWriteAccess) { return; @@ -336,7 +335,7 @@ export class SiteSummaryComponent implements OnDestroy { if (confirmResult) { let notificationId = null; - this._globalStateService.setBusyState(); + this._busyState.setBusyState(); this._portalService.startNotification( this.ts.instant(PortalResources.siteSummary_resetProfileNotifyTitle), this.ts.instant(PortalResources.siteSummary_resetProfileNotifyTitle)) @@ -346,14 +345,14 @@ export class SiteSummaryComponent implements OnDestroy { return this._armService.post(`${this.site.id}/newpassword`, null) }) .subscribe(response => { - this._globalStateService.clearBusyState(); + this._busyState.clearBusyState(); this._portalService.stopNotification( notificationId, true, this.ts.instant(PortalResources.siteSummary_resetProfileNotifySuccess)); }, e => { - this._globalStateService.clearBusyState(); + this._busyState.clearBusyState(); this._portalService.stopNotification( notificationId, false, @@ -375,7 +374,7 @@ export class SiteSummaryComponent implements OnDestroy { let appNode = this._viewInfo.node; let notificationId = null; - this._globalStateService.setBusyState(); + this._busyState.setBusyState(); this._portalService.startNotification( this.ts.instant(PortalResources.siteSummary_deleteNotifyTitle).format(site.name), this.ts.instant(PortalResources.siteSummary_deleteNotifyTitle).format(site.name)) @@ -398,12 +397,12 @@ export class SiteSummaryComponent implements OnDestroy { if (!this._isSlot) { appNode.sideNav.search(""); } - this._globalStateService.clearBusyState(); + this._busyState.clearBusyState(); appNode.parent.select(); (appNode).remove(); }, e => { - this._globalStateService.clearBusyState(); + this._busyState.clearBusyState(); this._portalService.stopNotification( notificationId, false, @@ -424,7 +423,7 @@ export class SiteSummaryComponent implements OnDestroy { let confirmResult = confirm(this.ts.instant(PortalResources.siteSummary_restartConfirmation).format(this.site.name)); if (confirmResult) { - this._globalStateService.setBusyState(); + this._busyState.setBusyState(); this._portalService.startNotification( this.ts.instant(PortalResources.siteSummary_restartNotifyTitle).format(site.name), @@ -435,14 +434,14 @@ export class SiteSummaryComponent implements OnDestroy { return this._armService.post(`${site.id}/restart`, null) }) .subscribe(() => { - this._globalStateService.clearBusyState(); + this._busyState.clearBusyState(); this._portalService.stopNotification( notificationId, true, this.ts.instant(PortalResources.siteSummary_restartNotifySuccess).format(site.name)); }, e => { - this._globalStateService.clearBusyState(); + this._busyState.clearBusyState(); this._portalService.stopNotification( notificationId, false, @@ -525,7 +524,7 @@ export class SiteSummaryComponent implements OnDestroy { ? this.ts.instant(PortalResources.siteSummary_stopNotifyTitle).format(site.name) : this.ts.instant(PortalResources.siteSummary_startNotifyTitle).format(site.name); - this._globalStateService.setBusyState(); + this._busyState.setBusyState(); this._portalService.startNotification(notifyTitle, notifyTitle) .first() @@ -560,7 +559,7 @@ export class SiteSummaryComponent implements OnDestroy { ? this.ts.instant(PortalResources.siteSummary_stopNotifyFail).format(site.name) : this.ts.instant(PortalResources.siteSummary_startNotifyFail).format(site.name); - this._globalStateService.clearBusyState(); + this._busyState.clearBusyState(); this._portalService.stopNotification( notificationId, false, diff --git a/AzureFunctions.AngularClient/src/app/tab/tab.component.ts b/AzureFunctions.AngularClient/src/app/tab/tab.component.ts index 97d556d842..4460737731 100644 --- a/AzureFunctions.AngularClient/src/app/tab/tab.component.ts +++ b/AzureFunctions.AngularClient/src/app/tab/tab.component.ts @@ -2,7 +2,6 @@ import { Component, Input } from '@angular/core'; @Component({ selector: 'tab', - styleUrls: ['../tabs/tabs.component.scss'], templateUrl: './tab.component.html' }) export class TabComponent { @@ -10,4 +9,5 @@ export class TabComponent { @Input() id : string; @Input() active = false; @Input() closeable = false; + @Input() iconUrl : string; } \ No newline at end of file diff --git a/AzureFunctions.AngularClient/src/app/tabs/tabs.component.html b/AzureFunctions.AngularClient/src/app/tabs/tabs.component.html index 703e0aed2e..45f6b344ac 100644 --- a/AzureFunctions.AngularClient/src/app/tabs/tabs.component.html +++ b/AzureFunctions.AngularClient/src/app/tabs/tabs.component.html @@ -1,15 +1,21 @@ -