diff --git a/AzureFunctions.AngularClient/src/app/function/embedded/embedded-function-editor/embedded-function-editor.component.ts b/AzureFunctions.AngularClient/src/app/function/embedded/embedded-function-editor/embedded-function-editor.component.ts index 266f662e4e..056f84c878 100644 --- a/AzureFunctions.AngularClient/src/app/function/embedded/embedded-function-editor/embedded-function-editor.component.ts +++ b/AzureFunctions.AngularClient/src/app/function/embedded/embedded-function-editor/embedded-function-editor.component.ts @@ -1,4 +1,3 @@ -import { ArmService } from 'app/shared/services/arm.service'; import { CdsFunctionDescriptor } from 'app/shared/resourceDescriptors'; import { errorIds } from 'app/shared/models/error-ids'; import { ErrorEvent } from 'app/shared/models/error-event'; @@ -18,7 +17,7 @@ import { TreeViewInfo } from './../../../tree-view/models/tree-view-info'; import { BroadcastService } from 'app/shared/services/broadcast.service'; import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core'; import { AfterContentInit } from '@angular/core/src/metadata/lifecycle_hooks'; -import { UserService } from 'app/shared/services/user.service'; +import { EmbeddedService } from 'app/shared/services/embedded.service'; @Component({ selector: 'embedded-function-editor', @@ -45,8 +44,7 @@ export class EmbeddedFunctionEditorComponent implements OnInit, AfterContentInit private _broadcastService: BroadcastService, private _cacheService: CacheService, private _translateService: TranslateService, - private _armService: ArmService, - private _userService: UserService) { + private _embeddedService: EmbeddedService) { this._busyManager = new BusyStateScopeManager(this._broadcastService, 'dashboard'); @@ -167,31 +165,23 @@ export class EmbeddedFunctionEditorComponent implements OnInit, AfterContentInit const result = confirm(this._translateService.instant(PortalResources.functionManage_areYouSure, { name: this._functionInfo.name })); if (result) { this._busyManager.setBusy(); - const headers = this._armService.getHeaders(); - this._userService.getStartupInfo() - .first() - .switchMap(info => { - headers.append('x-cds-crm-user-token', info.crmInfo.crmTokenHeaderName); - headers.append('x-cds-crm-org', info.crmInfo.crmInstanceHeaderName); - headers.append('x-cds-crm-solutionid', info.crmInfo.crmSolutionIdHeaderName); - - const url = this._armService.getArmUrl(this.resourceId, this._armService.websiteApiVersion); - return this._cacheService.delete(url, headers); - }) - .subscribe(r => { - this._busyManager.clearBusy(); - this._broadcastService.broadcastEvent(BroadcastEvent.TreeUpdate, { - resourceId: this.resourceId, - operation: 'remove' - }); - }, err => { - this._busyManager.clearBusy(); - this._broadcastService.broadcast(BroadcastEvent.Error, { - message: this._translateService.instant(PortalResources.error_unableToDeleteFunction).format(this._functionInfo.name), - errorId: errorIds.embeddedEditorDeleteError, - resourceId: this.resourceId, - }); - }); + this._embeddedService.deleteFunction(this.resourceId) + .subscribe(r => { + if (r.isSuccessful) { + this._busyManager.clearBusy(); + this._broadcastService.broadcastEvent(BroadcastEvent.TreeUpdate, { + resourceId: this.resourceId, + operation: 'remove' + }); + } else { + this._busyManager.clearBusy(); + this._broadcastService.broadcast(BroadcastEvent.Error, { + message: r.error.message, + errorId: r.error.errorId, + resourceId: this.resourceId, + }); + } + }); } } } diff --git a/AzureFunctions.AngularClient/src/app/function/embedded/models/entity.ts b/AzureFunctions.AngularClient/src/app/function/embedded/models/entity.ts new file mode 100644 index 0000000000..1ae602b4e1 --- /dev/null +++ b/AzureFunctions.AngularClient/src/app/function/embedded/models/entity.ts @@ -0,0 +1,4 @@ +export interface Entity { + name: string; + displayName: string; +} diff --git a/AzureFunctions.AngularClient/src/app/function/function-new-detail/function-new-detail.component.ts b/AzureFunctions.AngularClient/src/app/function/function-new-detail/function-new-detail.component.ts index b11b0e06bc..8adfc2eccb 100644 --- a/AzureFunctions.AngularClient/src/app/function/function-new-detail/function-new-detail.component.ts +++ b/AzureFunctions.AngularClient/src/app/function/function-new-detail/function-new-detail.component.ts @@ -1,4 +1,3 @@ -import { ArmService } from './../../shared/services/arm.service'; import { ArmEmbeddedService } from './../../shared/services/arm-embedded.service'; import { KeyCodes, LogCategories } from './../../shared/models/constants'; import { TreeViewInfo } from 'app/tree-view/models/tree-view-info'; @@ -25,7 +24,7 @@ import { UIFunctionBinding } from '../../shared/models/binding'; import { PortalService } from '../../shared/services/portal.service'; import { Observable } from 'rxjs/Observable'; import { CreateCard } from 'app/function/function-new/function-new.component'; -import { UserService } from 'app/shared/services/user.service'; +import { EmbeddedService } from 'app/shared/services/embedded.service'; @Component({ selector: 'function-new-detail', @@ -34,8 +33,6 @@ import { UserService } from 'app/shared/services/user.service'; }) export class FunctionNewDetailComponent implements OnChanges { - // TODO: ellhamai - figure out where to put this - private _cdsEntitiesUrl = 'https://tip1.api.cds.microsoft.com/providers/Microsoft.CommonDataModel/environments/0fb7e803-94aa-4e69-9694-d3b3cea74523/namespaces/5d5374aa-0df3-421c-9656-5244ac88593c/entities?api-version=2016-11-01-alpha&$expand=namespace&headeronly=true'; private _bindingComponents: BindingComponent[] = []; @Input() functionCard: CreateCard; @@ -81,8 +78,7 @@ export class FunctionNewDetailComponent implements OnChanges { private _cacheService: CacheService, private _functionAppService: FunctionAppService, private _logService: LogService, - private _armService: ArmService, - private _userService: UserService) { + private _embeddedService: EmbeddedService) { this.isEmbedded = this._portalService.isEmbeddedFunctions; } @@ -93,7 +89,7 @@ export class FunctionNewDetailComponent implements OnChanges { this.updateLanguageOptions(); if (this._portalService.isEmbeddedFunctions) { - this._getEntities(); + this.getEntityOptions(); } } } @@ -125,6 +121,23 @@ export class FunctionNewDetailComponent implements OnChanges { } } + getEntityOptions() { + this._embeddedService.getEntities() + .subscribe(r => { + if (r.isSuccessful) { + const entities = (r.result.value.map(e => e.name)).sort(); + this.entityOptions = []; + entities.forEach(entity => { + const dropDownElement: any = { + displayLabel: entity, + value: entity + }; + this.entityOptions.push(dropDownElement); + }); + } + }); + } + onEntityChanged(entity: string) { this.areInputsValid = false; this.functionEntity = entity.toLowerCase(); @@ -300,31 +313,6 @@ export class FunctionNewDetailComponent implements OnChanges { } } - private _getEntities() { - const url = this._cdsEntitiesUrl; - const headers = this._armService.getHeaders(); - this._userService.getStartupInfo() - .first() - .switchMap(info => { - headers.append('x-cds-crm-user-token', info.crmInfo.crmTokenHeaderName); - headers.append('x-cds-crm-org', info.crmInfo.crmInstanceHeaderName); - headers.append('x-cds-crm-solutionid', info.crmInfo.crmSolutionIdHeaderName); - - return this._cacheService.get(url, null, headers).map(r => r.json()); - }) - .subscribe(r => { - const entities = (r.value.map(e => e.name)).sort(); - this.entityOptions = []; - entities.forEach(entity => { - const dropDownElement: any = { - displayLabel: entity, - value: entity - }; - this.entityOptions.push(dropDownElement); - }); - }); - } - private _createFunction() { this._portalService.logAction('new-function', 'creating', { template: this.currentTemplate.id, name: this.functionName }); diff --git a/AzureFunctions.AngularClient/src/app/functions-list/functions-list.component.ts b/AzureFunctions.AngularClient/src/app/functions-list/functions-list.component.ts index 3a8c173cf6..d70e34fdaa 100644 --- a/AzureFunctions.AngularClient/src/app/functions-list/functions-list.component.ts +++ b/AzureFunctions.AngularClient/src/app/functions-list/functions-list.component.ts @@ -1,8 +1,6 @@ -import { ArmService } from './../shared/services/arm.service'; import { ArmSiteDescriptor } from './../shared/resourceDescriptors'; import { FunctionAppContext } from './../shared/function-app-context'; import { TreeUpdateEvent, BroadcastEvent } from './../shared/models/broadcast-event'; -import { CacheService } from 'app/shared/services/cache.service'; import { FunctionInfo } from 'app/shared/models/function-info'; import { CreateCard } from 'app/function/function-new/function-new.component'; import { DashboardType } from 'app/tree-view/models/dashboard-type'; @@ -20,7 +18,8 @@ import { Observable } from 'rxjs/Observable'; import { FunctionAppService } from 'app/shared/services/function-app.service'; import { Subscription } from 'rxjs/Subscription'; import { NavigableComponent } from '../shared/components/navigable-component'; -import { UserService } from 'app/shared/services/user.service'; +import { EmbeddedService } from 'app/shared/services/embedded.service'; +import { ErrorEvent } from 'app/shared/models/error-event'; @Component({ selector: 'functions-list', @@ -49,9 +48,8 @@ export class FunctionsListComponent extends NavigableComponent implements OnDest private _translateService: TranslateService, broadcastService: BroadcastService, private _functionAppService: FunctionAppService, - private _cacheService: CacheService, - private _armService: ArmService, - private _userService: UserService) { + private _embeddedService: EmbeddedService) { + super('functions-list', broadcastService, DashboardType.FunctionsDashboard); this.isEmbedded = this._portalService.isEmbeddedFunctions; @@ -206,28 +204,22 @@ export class FunctionsListComponent extends NavigableComponent implements OnDest const result = confirm(this._translateService.instant(PortalResources.functionManage_areYouSure, { name: item.functionInfo.name })); if (result) { this._globalStateService.setBusyState(); - - const headers = this._armService.getHeaders(); - this._userService.getStartupInfo() - .first() - .switchMap(info => { - headers.append('x-cds-crm-user-token', info.crmInfo.crmTokenHeaderName); - headers.append('x-cds-crm-org', info.crmInfo.crmInstanceHeaderName); - headers.append('x-cds-crm-solutionid', info.crmInfo.crmSolutionIdHeaderName); - - const url = this._armService.getArmUrl(item.resourceId, this._armService.websiteApiVersion); - return this._cacheService.delete(url, headers); - }) + this._embeddedService.deleteFunction(item.resourceId) .subscribe(r => { - this._globalStateService.clearBusyState(); - this._broadcastService.broadcastEvent(BroadcastEvent.TreeUpdate, { - resourceId: item.resourceId, - operation: 'remove' - }); - - }, err => { - this._globalStateService.clearBusyState(); - // TODO: ellhamai - handle error + if (r.isSuccessful) { + this._globalStateService.clearBusyState(); + this._broadcastService.broadcastEvent(BroadcastEvent.TreeUpdate, { + resourceId: item.resourceId, + operation: 'remove' + }); + } else { + this._globalStateService.clearBusyState(); + this._broadcastService.broadcast(BroadcastEvent.Error, { + message: r.error.message, + errorId: r.error.errorId, + resourceId: item.resourceId, + }); + } }); } } diff --git a/AzureFunctions.AngularClient/src/app/shared/models/error-ids.ts b/AzureFunctions.AngularClient/src/app/shared/models/error-ids.ts index dc94692204..72ad395715 100644 --- a/AzureFunctions.AngularClient/src/app/shared/models/error-ids.ts +++ b/AzureFunctions.AngularClient/src/app/shared/models/error-ids.ts @@ -62,4 +62,5 @@ export namespace errorIds { export const embeddedEditorLoadError = '/errors/embedded/editor-load'; export const embeddedEditorSaveError = '/errors/embedded/editor-save'; export const embeddedEditorDeleteError = '/errors/embedded/editor-delete'; + export const embeddedGetEntities = '/errors/embedded/get-entities'; } diff --git a/AzureFunctions.AngularClient/src/app/shared/models/portal.ts b/AzureFunctions.AngularClient/src/app/shared/models/portal.ts index bb94994a42..5a993b11c1 100644 --- a/AzureFunctions.AngularClient/src/app/shared/models/portal.ts +++ b/AzureFunctions.AngularClient/src/app/shared/models/portal.ts @@ -31,6 +31,8 @@ export interface CrmInfo { crmTokenHeaderName: string; crmInstanceHeaderName: string; crmSolutionIdHeaderName: string; + environmentId: string; + namespaceId: string; } export interface DataMessage{ diff --git a/AzureFunctions.AngularClient/src/app/shared/services/embedded.service.ts b/AzureFunctions.AngularClient/src/app/shared/services/embedded.service.ts new file mode 100644 index 0000000000..3f0abc8566 --- /dev/null +++ b/AzureFunctions.AngularClient/src/app/shared/services/embedded.service.ts @@ -0,0 +1,90 @@ +import { StartupInfo } from 'app/shared/models/portal'; +import { ArmService } from 'app/shared/services/arm.service'; +import { errorIds } from 'app/shared/models/error-ids'; +import { Entity } from './../../function/embedded/models/entity'; +import { ArmArrayResult } from './../models/arm/arm-obj'; +import { FunctionAppHttpResult } from './../models/function-app-http-result'; +import { Observable } from 'rxjs/Observable'; +import { CacheService } from 'app/shared/services/cache.service'; +import { Injectable } from '@angular/core'; +import { UserService } from 'app/shared/services/user.service'; +import { Response } from '@angular/http'; + +@Injectable() +export class EmbeddedService { + private _cdsEntitiesUrlFormat = 'https://tip1.api.cds.microsoft.com/providers/Microsoft.CommonDataModel/environments/{0}/namespaces/{1}/entities?api-version=2016-11-01-alpha&$expand=namespace&headeronly=true'; + + constructor( + private _userService: UserService, + private _cacheService: CacheService, + private _armService: ArmService) { } + + deleteFunction(resourceId: string): Observable> { + return this._userService.getStartupInfo() + .first() + .switchMap(info => { + const headers = this._getHeaders(info); + const url = this._armService.getArmUrl(resourceId, this._armService.websiteApiVersion); + return this._cacheService.delete(url, headers); + }) + .map(r => { + const result: FunctionAppHttpResult = { + isSuccessful: true, + error: null, + result: null + }; + return result; + }) + .catch(e => { + const result: FunctionAppHttpResult = { + isSuccessful: false, + error: { + errorId: errorIds.embeddedEditorDeleteError, + message: 'Failed to delete function' + }, + result: null + }; + + return Observable.of(result); + }); + } + + getEntities(): Observable>> { + return this._userService + .getStartupInfo() + .first() + .switchMap(info => { + const headers = this._getHeaders(info); + const url = this._cdsEntitiesUrlFormat.format(info.crmInfo.environmentId, info.crmInfo.namespaceId); + return this._cacheService.get(url, false, headers); + }) + .map((r: Response) => { + const result: FunctionAppHttpResult> = { + isSuccessful: true, + error: null, + result: r.json() + }; + return result; + }) + .catch(e => { + const result: FunctionAppHttpResult> = { + isSuccessful: false, + error: { + errorId: errorIds.embeddedGetEntities, + message: 'Failed to get entitites' + }, + result: null + }; + + return Observable.of(result); + }); + } + + private _getHeaders(info: StartupInfo){ + const headers = this._armService.getHeaders(); + headers.append('x-cds-crm-user-token', info.crmInfo.crmTokenHeaderName); + headers.append('x-cds-crm-org', info.crmInfo.crmInstanceHeaderName); + headers.append('x-cds-crm-solutionid', info.crmInfo.crmSolutionIdHeaderName); + return headers; + } +} diff --git a/AzureFunctions.AngularClient/src/app/shared/shared.module.ts b/AzureFunctions.AngularClient/src/app/shared/shared.module.ts index c05df508b6..85b060cbc2 100644 --- a/AzureFunctions.AngularClient/src/app/shared/shared.module.ts +++ b/AzureFunctions.AngularClient/src/app/shared/shared.module.ts @@ -61,6 +61,7 @@ import { TableRowComponent } from './../controls/table-row/table-row.component'; import { TableRootComponent } from './../controls/table-root/table-root.component'; import { DeletedItemsFilter } from './../controls/table-root/deleted-items-filter.pipe'; import { ActivateWithKeysDirective } from './../controls/activate-with-keys/activate-with-keys.directive'; +import { EmbeddedService } from 'app/shared/services/embedded.service'; export function ArmServiceFactory( http: Http, @@ -195,6 +196,7 @@ export class SharedModule { UtilitiesService, BackgroundTasksService, GlobalStateService, + EmbeddedService, { provide: AiService, useFactory: AiServiceFactory }, { provide: ErrorHandler, useClass: GlobalErrorHandler } ]