Skip to content

Commit

Permalink
Merge pull request #2828 from cloudfoundry-incubator/redeploy-app
Browse files Browse the repository at this point in the history
Add restage to application page.
  • Loading branch information
nwmac authored Sep 11, 2018
2 parents 93d13b1 + fc6036b commit 028cef2
Show file tree
Hide file tree
Showing 11 changed files with 108 additions and 107 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ <h1>{{ application?.app?.entity?.name }} </h1>
<a class="app-page-header__anchor" mat-icon-button *ngIf="(applicationService.applicationUrl$ | async) != null && application?.app.entity.state === 'STARTED'" href="{{applicationService.applicationUrl$ | async}}" target="_blank" matTooltip="Visit">
<mat-icon>launch</mat-icon>
</a>
<span *ngIf="isBusyUpdating$ | async as busy">
<span *ngIf="applicationService.appSpace$ | async as space">
<span class="manage-application-actions" *appUserPermission="manageAppPermission;spaceGuid:space.metadata.guid;endpointGuid:this.applicationService.cfGuid">
<button mat-icon-button name="edit" *ngIf="(this.applicationService.applicationState$ | async)" routerLink="/applications/{{applicationService.cfGuid}}/{{applicationService.appGuid}}/edit" matTooltip="Edit">
Expand All @@ -13,22 +14,25 @@ <h1>{{ application?.app?.entity?.name }} </h1>
<button mat-icon-button name="delete" (click)="redirectToDeletePage()" matTooltip="Delete">
<mat-icon>delete</mat-icon>
</button>
<div *ngIf="appActions$ | async as appActions" class="app-page-header__actions">
<button mat-icon-button name="restart" *ngIf="appActions.restart" (click)="restartApplication()" matTooltip="Restart">
<div *ngIf="applicationService.applicationState$ | async as appState" class="app-page-header__actions">
<button mat-icon-button name="restart" [disabled]="busy.updating || !appState.actions.restart" (click)="restartApplication()" matTooltip="Restart">
<mat-icon>settings_backup_restore</mat-icon>
</button>
<button mat-icon-button name="stop" *ngIf="appActions.stop" (click)="stopApplication()" matTooltip="Stop">
<button mat-icon-button name="stop" [disabled]="busy.updating" *ngIf="appState.actions.stop;else startButton" (click)="stopApplication()" matTooltip="Stop">
<mat-icon>stop</mat-icon>
</button>
<button mat-icon-button name="start" *ngIf="appActions.start" (click)="startApplication()" matTooltip="Start">
<mat-icon>play_arrow</mat-icon>
</button>
<button mat-icon-button name="cli" routerLink="/applications/{{applicationService.cfGuid}}/{{applicationService.appGuid}}/cli" matTooltip="CLI Info">
<mat-icon>keyboard</mat-icon>
<ng-template #startButton>
<button mat-icon-button name="start" [disabled]="busy.updating || !appState.actions.start && !appState.actions.stop" (click)="startApplication()" matTooltip="Start">
<mat-icon>play_arrow</mat-icon>
</button>
</ng-template>
<button mat-icon-button name="restage" [disabled]="busy.updating || !appState.actions.restage" (click)="restageApplication()" matTooltip="Restage">
<mat-icon>redo</mat-icon>
</button>
</div>
</span>
</span>
</span>
</div>
</div>
</app-page-header>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Component, Inject, NgZone, OnDestroy, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { Store } from '@ngrx/store';
import { combineLatest as observableCombineLatest, Observable, of as observableOf, Subscription } from 'rxjs';
import { delay, filter, first, map, mergeMap, tap, withLatestFrom } from 'rxjs/operators';
import { delay, filter, first, map, mergeMap, tap, withLatestFrom, startWith } from 'rxjs/operators';
import { IApp, IOrganization, ISpace } from '../../../../core/cf-api.types';
import { CurrentUserPermissions } from '../../../../core/current-user-permissions.config';
import { EntityService } from '../../../../core/entity-service';
Expand All @@ -22,6 +22,9 @@ import { APIResource } from '../../../../store/types/api.types';
import { EndpointModel } from '../../../../store/types/endpoint.types';
import { ApplicationService } from '../../application.service';
import { EndpointsService } from './../../../../core/endpoints.service';
import { RestageApplication } from '../../../../store/actions/application.actions';
import { ApplicationStateData } from '../../../../shared/components/application-state/application-state.service';
import { ActionState } from '../../../../store/reducers/api-request-reducer/types';


// Confirmation dialogs
Expand Down Expand Up @@ -56,6 +59,8 @@ const appDeleteConfirmation = new ConfirmationDialogConfig(
export class ApplicationTabsBaseComponent implements OnInit, OnDestroy {
public schema = entityFactory(applicationSchemaKey);
public manageAppPermission = CurrentUserPermissions.APPLICATION_MANAGE;
public appState$: Observable<ApplicationStateData>;
isBusyUpdating$: Observable<{ updating: boolean }>;
constructor(
private route: ActivatedRoute,
private router: Router,
Expand Down Expand Up @@ -110,7 +115,6 @@ export class ApplicationTabsBaseComponent implements OnInit, OnDestroy {
appSub$: Subscription;
entityServiceAppRefresh$: Subscription;
autoRefreshString = 'auto-refresh';
appActions$: Observable<{ [key: string]: boolean }>;

autoRefreshing$ = this.entityService.updatingSection$.pipe(map(
update => update[this.autoRefreshString] || { busy: false }
Expand Down Expand Up @@ -216,11 +220,16 @@ export class ApplicationTabsBaseComponent implements OnInit, OnDestroy {
});
}

restageApplication() {
const { cfGuid, appGuid } = this.applicationService;
this.store.dispatch(new RestageApplication(appGuid, cfGuid));
}

pollEntityService(state, stateString): Observable<any> {
return this.entityService
.poll(1000, state).pipe(
delay(1),
filter(({ resource, updatingSection }) => {
filter(({ resource }) => {
return resource.entity.state === stateString;
}),
);
Expand All @@ -235,6 +244,10 @@ export class ApplicationTabsBaseComponent implements OnInit, OnDestroy {
this.store.dispatch(new GetAppStatsAction(appGuid, cfGuid));
}

private updatingSectionBusy(section: ActionState) {
return section && section.busy;
}

restartApplication() {
this.confirmDialog.open(appRestartConfirmation, () => {

Expand Down Expand Up @@ -288,6 +301,15 @@ export class ApplicationTabsBaseComponent implements OnInit, OnDestroy {

this.isFetching$ = this.applicationService.isFetchingApp$;

this.isBusyUpdating$ = this.entityService.updatingSection$.pipe(
map(updatingSection => {
const updating = this.updatingSectionBusy(updatingSection['restaging']) ||
this.updatingSectionBusy(updatingSection['Updating-Existing-Application']);
return { updating };
}),
startWith({ updating: true })
);

const initialFetch$ = observableCombineLatest(
this.applicationService.isFetchingApp$,
this.applicationService.isFetchingEnvVars$,
Expand All @@ -307,10 +329,6 @@ export class ApplicationTabsBaseComponent implements OnInit, OnDestroy {
}
return !!(isFetchingApp || isUpdating);
}));

this.appActions$ = this.applicationService.applicationState$.pipe(
map(app => app.actions)
);
}

ngOnDestroy() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@
<div class="app-metadata__two-cols">
<app-metadata-item icon="touch_app" label="App State">{{ appSvc.app.entity.state }}</app-metadata-item>
<app-metadata-item icon="card_travel" label="Package State">{{ appSvc.app.entity.package_state }}</app-metadata-item>
<app-metadata-item icon="service" iconFont="stratos-icons" label="Services">{{(applicationService.appSummary$| async)?.entity?.entity.services?.length || '0' }}</app-metadata-item>
<app-metadata-item icon="network_route" iconFont="stratos-icons" label="Routes">{{(applicationService.appSummary$| async)?.entity?.entity?.routes?.length || '0' }}</app-metadata-item>
<app-metadata-item icon="service" iconFont="stratos-icons" label="Services">{{(applicationService.appSummary$ | async)?.entity?.entity.services?.length || '0' }}</app-metadata-item>
<app-metadata-item icon="network_route" iconFont="stratos-icons" label="Routes">{{(applicationService.appSummary$ | async)?.entity?.entity?.routes?.length || '0' }}</app-metadata-item>
</div>
</div>
</mat-card-content>
Expand All @@ -52,6 +52,9 @@
<app-metadata-item *ngIf="applicationService.appSpace$ | async as appSpace" icon="language" label="Space">
<a [routerLink]="['/cloud-foundry/' + appSvc.cf?.guid + '/organizations/' + appOrg.metadata?.guid + '/spaces/' + appSpace.metadata?.guid]">{{ appSpace.entity.name }}</a>
</app-metadata-item>
<app-metadata-item icon="keyboard" label="CLI Info" class="cli-link">
<a [routerLink]="['/applications/' + appSvc.cf?.guid + '/' + appSvc.app?.metadata.guid + '/cli']">View</a>
</app-metadata-item>
</ng-container>
</mat-card-content>
</mat-card>
Expand Down Expand Up @@ -83,7 +86,7 @@
<app-metadata-item *ngSwitchCase="'giturl'" icon="code" label="Git Url">
<div matTooltip="{{ deploySource.branch + ' ' + (deploySource.commit | slice:0:8)}}"
[matTooltipHideDelay]="1500">
{{(applicationService.applicationStratProject$| async)?.deploySource.url}}
{{(applicationService.applicationStratProject$| async)?.deploySource.url}}
</div>
</app-metadata-item>
<app-metadata-item *ngSwitchCase="'github'" iconFont="stratos-icons" icon="github" label="GitHub">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,7 @@
}
}
}

.cli-link {
margin-top: 24px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { ApplicationData, ApplicationService } from '../../../../application.ser
export class BuildTabComponent implements OnInit {


constructor(private route: ActivatedRoute, public applicationService: ApplicationService, private store: Store<AppState>) { }
constructor(public applicationService: ApplicationService) { }

cardTwoFetching$: Observable<boolean>;

Expand All @@ -45,11 +45,11 @@ export class BuildTabComponent implements OnInit {
this.sshStatus$ = this.applicationService.application$.pipe(
combineLatest(this.applicationService.appSpace$),
map(([app, space]) => {
if (! space.entity.allow_ssh) {
if (!space.entity.allow_ssh) {
return 'Disabled by the space';
} else {
return app.app.entity.enable_ssh ? 'Yes' : 'No';
}
}
})
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,5 @@
<app-page-header [breadcrumbs]="breadcrumbs$ | async">
<h1>CLI Info</h1>
<div class="page-header-right">
<span>
<button mat-icon-button (click)="back()">
<mat-icon matTooltip="Back to App">close</mat-icon>
</button>
</span>
</div>
</app-page-header>

<app-cli-info *ngIf="context$ | async as context" [context]="context">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { ApplicationService } from '../application.service';
import { AppState } from '../../../store/app-state';
import { Store } from '@ngrx/store';
import { getPreviousRoutingState, RoutingEvent } from '../../../store/types/routing.type';
import { first, map, filter } from 'rxjs/operators';
import { RouterNav } from '../../../store/actions/router.actions';
import { ActivatedRoute } from '@angular/router';
import { Component, OnInit } from '@angular/core';
import { BehaviorSubject, combineLatest, Observable } from 'rxjs';
import { filter, first, map } from 'rxjs/operators';
import { EntityServiceFactory } from '../../../core/entity-service-factory.service';
import { APIResource } from '../../../store/types/api.types';
import { endpointSchemaKey, entityFactory } from '../../../store/helpers/entity-factory';
import { CFAppCLIInfoContext } from '../../../shared/components/cli-info/cli-info.component';
import { IHeaderBreadcrumb } from '../../../shared/components/page-header/page-header.types';
import { GetAllEndpoints } from '../../../store/actions/endpoint.actions';
import { combineLatest , Observable , BehaviorSubject } from 'rxjs';
import { endpointSchemaKey, entityFactory } from '../../../store/helpers/entity-factory';
import { getFullEndpointApiUrl } from '../../endpoints/endpoint-helpers';
import { IApp } from '../../../core/cf-api.types';
import { IHeaderBreadcrumb } from '../../../shared/components/page-header/page-header.types';
import { CFAppCLIInfoContext } from '../../../shared/components/cli-info/cli-info.component';
import { ApplicationService } from '../application.service';

@Component({
selector: 'app-cli-info-application',
Expand All @@ -31,10 +24,8 @@ export class CliInfoApplicationComponent implements OnInit {

public context$: Observable<CFAppCLIInfoContext>;
public breadcrumbs$: Observable<IHeaderBreadcrumb[]>;
public route$: Observable<{ url: string, queryParams: any }>;

constructor(
private store: Store<AppState>,
private applicationService: ApplicationService,
private entityServiceFactory: EntityServiceFactory
) {
Expand All @@ -43,32 +34,10 @@ export class CliInfoApplicationComponent implements OnInit {

ngOnInit() {
const { cfGuid, appGuid } = this.applicationService;
const defaultBackLink = (
`/applications/${cfGuid}/${appGuid}`
);

this.setupRouteObservable(defaultBackLink);
// Will auto unsubscribe as we are using 'first'
this.route$.pipe(first()).subscribe(route => {
this.previousUrl = route.url;
this.previousQueryParams = route.queryParams;
});

this.setupObservables(cfGuid);
this.setupBreadcrumbs(cfGuid, appGuid);
}

private setupRouteObservable(defaultBackLink: string) {
this.route$ = this.store.select(getPreviousRoutingState).pipe(
map(route => {
return {
url: route && route.state ? route.state.url : defaultBackLink,
queryParams: route && route.state.queryParams ? route.state.queryParams : {}
};
})
);
}

private setupObservables(cfGuid: string) {
this.cfEndpointEntityService = this.entityServiceFactory.create(
endpointSchemaKey,
Expand Down Expand Up @@ -97,28 +66,17 @@ export class CliInfoApplicationComponent implements OnInit {
}

setupBreadcrumbs(cfGuid: string, appGuid: string) {
this.breadcrumbs$ = combineLatest(
this.route$,
this.context$
).pipe(
map(([route, context]) => {
this.breadcrumbs$ = this.context$.pipe(
map((context) => {
return [
{
breadcrumbs: [
{ value: 'Applications', routerLink: '/applications' },
{ value: context.appName, routerLink: route.url }
{ value: context.appName, routerLink: `/applications/${cfGuid}/${appGuid}` }
]
}
];
}));
}

back() {
this.store.dispatch(new RouterNav({
path: this.previousUrl,
query: this.previousQueryParams
}
));
})
);
}

}
Loading

0 comments on commit 028cef2

Please sign in to comment.