Skip to content

Commit d3d199d

Browse files
FWT-929: Add cross-tab navigation to app summary cards
- Instances card (summary page) navigates to Instances tab - Status and Uptime cards navigate back to Summary tab - Vertically center non-graph cells in instance table rows - Fix action button positioning (top/right spacing now equal) - Add provideRouter([]) to card-app-status and instances-tab specs
1 parent 7adcb42 commit d3d199d

10 files changed

Lines changed: 69 additions & 40 deletions

File tree

src/frontend/packages/cloud-foundry/src/features/applications/application/application-tabs-base/tabs/instances-tab/instances-tab.component.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
22
import { provideHttpClient } from '@angular/common/http';
33
import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing';
44
import { provideZonelessChangeDetection, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
5+
import { provideRouter } from '@angular/router';
56
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
67
import { of } from 'rxjs';
78
import { Store } from '@ngrx/store';
@@ -54,6 +55,7 @@ describe('InstancesTabComponent', () => {
5455
provideHttpClient(),
5556
provideHttpClientTesting(),
5657
provideZonelessChangeDetection(),
58+
provideRouter([]),
5759
{ provide: Store, useValue: mockStore },
5860
{ provide: PaginationMonitorFactory, useValue: mockPmf },
5961
{ provide: ApplicationService, useClass: ApplicationServiceMock },

src/frontend/packages/cloud-foundry/src/shared/components/cards/card-app-instances/card-app-instances.component.html

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,37 @@
11
<div class="card-app-instances block p-4 rounded bg-[var(--card-bg)] text-[color:var(--content-text)] border border-[color:var(--card-border)] shadow-none h-full">
22
<app-card-status [status$]="status$"></app-card-status>
3-
<div class="card-header">
4-
<h2 class="card-title">Instances</h2>
5-
</div>
6-
<div class="card-content card-app-instances__compact">
7-
@if (!isEditing) {
8-
<div class="card-app-instances__large">
9-
<app-running-instances [instances]="(appService.application$ | async)?.app.entity?.instances"
10-
[cfGuid]="appService.cfGuid" [appGuid]="this.appService.appGuid">
11-
</app-running-instances>
3+
@if (!showActions) {
4+
<a class="block no-underline cursor-pointer" [routerLink]="['../instances']" title="Go to Instances tab">
5+
<div class="card-header">
6+
<h2 class="card-title">Instances</h2>
127
</div>
13-
}
14-
<form [hidden]="!isEditing" class="card-app-instances__form">
15-
<app-form-field>
16-
<input #instanceField appInput type="number" name="instances" [(ngModel)]="editValue" value="{{ editCount }}">
17-
</app-form-field>
18-
</form>
19-
</div>
8+
<div class="card-content card-app-instances__compact">
9+
<div class="card-app-instances__large">
10+
<app-running-instances [instances]="(appService.application$ | async)?.app.entity?.instances"
11+
[cfGuid]="appService.cfGuid" [appGuid]="this.appService.appGuid">
12+
</app-running-instances>
13+
</div>
14+
</div>
15+
</a>
16+
} @else {
17+
<div class="card-header">
18+
<h2 class="card-title">Instances</h2>
19+
</div>
20+
<div class="card-content card-app-instances__compact">
21+
@if (!isEditing) {
22+
<div class="card-app-instances__large">
23+
<app-running-instances [instances]="(appService.application$ | async)?.app.entity?.instances"
24+
[cfGuid]="appService.cfGuid" [appGuid]="this.appService.appGuid">
25+
</app-running-instances>
26+
</div>
27+
}
28+
<form [hidden]="!isEditing" class="card-app-instances__form">
29+
<app-form-field>
30+
<input #instanceField appInput type="number" name="instances" [(ngModel)]="editValue" value="{{ editCount }}">
31+
</app-form-field>
32+
</form>
33+
</div>
34+
}
2035
@if (canEditApp$ | async) {
2136
@if (showActions && (appService.applicationRunning$ | async) && !isEditing) {
2237
<div

src/frontend/packages/cloud-foundry/src/shared/components/cards/card-app-instances/card-app-instances.component.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,10 @@
1010
}
1111

1212
&__actions {
13-
bottom: 24px;
13+
top: 16px;
1414
padding-top: 0;
1515
position: absolute;
16-
right: 24px;
16+
right: 16px;
1717
text-align: right;
1818
}
1919

src/frontend/packages/cloud-foundry/src/shared/components/cards/card-app-instances/card-app-instances.component.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Component, ElementRef, Input, OnDestroy, OnInit, Renderer2, ViewChild, ChangeDetectionStrategy, inject } from '@angular/core';
22
import { CommonModule } from '@angular/common';
33
import { FormsModule } from '@angular/forms';
4+
import { RouterLink } from '@angular/router';
45
import { combineLatest, Observable, Subscription } from 'rxjs';
56
import { take, map, switchMap } from 'rxjs/operators';
67

@@ -32,6 +33,7 @@ const appInstanceScaleToZeroConfirmation = new ConfirmationDialogConfig('Set Ins
3233
imports: [
3334
CommonModule,
3435
FormsModule,
36+
RouterLink,
3537
AppInputDirective,
3638
CustomFormFieldComponent,
3739
CardStatusComponent,
Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
<div class="card-app-status block p-4 rounded bg-[var(--card-bg)] text-[color:var(--content-text)] border border-[color:var(--card-border)] shadow-none h-full">
22
<app-card-status [status$]="status$"></app-card-status>
3-
<div class="card-header">
4-
<h2 class="card-title">Status</h2>
5-
</div>
6-
<div class="card-content">
7-
<div class="card-app-status__large">
8-
<app-application-state [state]="applicationService.applicationState$"></app-application-state>
3+
<a class="block no-underline cursor-pointer" [routerLink]="['../summary']" title="Go to Summary tab">
4+
<div class="card-header">
5+
<h2 class="card-title">Status</h2>
96
</div>
10-
</div>
7+
<div class="card-content">
8+
<div class="card-app-status__large">
9+
<app-application-state [state]="applicationService.applicationState$"></app-application-state>
10+
</div>
11+
</div>
12+
</a>
1113
</div>

src/frontend/packages/cloud-foundry/src/shared/components/cards/card-app-status/card-app-status.component.spec.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ComponentFixture, TestBed } from '@angular/core/testing';
22
import { provideZonelessChangeDetection } from '@angular/core';
3+
import { provideRouter } from '@angular/router';
34
import { describe, it, expect, beforeEach, afterEach, beforeAll, afterAll, vi } from 'vitest';
45

56
import {
@@ -28,6 +29,7 @@ describe('CardAppStatusComponent', () => {
2829
],
2930
providers: [
3031
provideZonelessChangeDetection(),
32+
provideRouter([]),
3133
]
3234
})
3335
.overrideProvider(ApplicationService, { useValue: new ApplicationServiceMock() })

src/frontend/packages/cloud-foundry/src/shared/components/cards/card-app-status/card-app-status.component.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Component, OnInit, inject, ChangeDetectionStrategy } from '@angular/cor
22
import { Observable } from 'rxjs';
33
import { map } from 'rxjs/operators';
44

5+
import { RouterLink } from '@angular/router';
56
import { ApplicationStateComponent, CardStatusComponent } from '@stratosui/core';
67
import { StratosStatus } from '@stratosui/store';
78
import { ApplicationService } from '../../../../features/applications/application.service';
@@ -13,6 +14,7 @@ import { ApplicationService } from '../../../../features/applications/applicatio
1314
changeDetection: ChangeDetectionStrategy.OnPush,
1415
standalone: true,
1516
imports: [
17+
RouterLink,
1618
CardStatusComponent,
1719
ApplicationStateComponent
1820
]

src/frontend/packages/cloud-foundry/src/shared/components/cards/card-app-uptime/card-app-uptime.component.html

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
@if (appData$ | async; as appData) {
22
<div class="card-app-uptime block p-4 rounded bg-[var(--card-bg)] text-[color:var(--content-text)] border border-[color:var(--card-border)] shadow-none h-full">
33
@if (appService.applicationRunning$ | async) {
4-
<div class="card-app-uptime__contents">
5-
<div class="card-app-uptime__main">
6-
<div class="card-header">
7-
<h2 class="card-title">Uptime</h2>
8-
</div>
9-
<div class="card-content card-app-uptime__compact">
10-
<div class="card-app-uptime__large">{{ appData.maxUptime | uptime }}</div>
4+
<a class="block no-underline cursor-pointer" [routerLink]="['../summary']" title="Go to Summary tab">
5+
<div class="card-app-uptime__contents">
6+
<div class="card-app-uptime__main">
7+
<div class="card-header">
8+
<h2 class="card-title">Uptime</h2>
9+
</div>
10+
<div class="card-content card-app-uptime__compact">
11+
<div class="card-app-uptime__large">{{ appData.maxUptime | uptime }}</div>
12+
</div>
1113
</div>
14+
@if (appData.runningCount > 1) {
15+
<div class="card-app-uptime__detail">
16+
<app-metadata-item class="card-app-uptime__metric" label="Average">{{ appData.averageUptime | uptime }}</app-metadata-item>
17+
<app-metadata-item class="card-app-uptime__metric" label="Minimum">{{ appData.minUptime | uptime }}</app-metadata-item>
18+
</div>
19+
}
1220
</div>
13-
@if (appData.runningCount > 1) {
14-
<div class="card-app-uptime__detail">
15-
<app-metadata-item class="card-app-uptime__metric" label="Average">{{ appData.averageUptime | uptime }}</app-metadata-item>
16-
<app-metadata-item class="card-app-uptime__metric" label="Minimum">{{ appData.minUptime | uptime }}</app-metadata-item>
17-
</div>
18-
}
19-
</div>
21+
</a>
2022
} @else {
2123
<div class="block p-4 rounded bg-[var(--card-bg)] text-[color:var(--content-text)] border border-[color:var(--card-border)] shadow-none h-full">
2224
<div class="card-content">

src/frontend/packages/cloud-foundry/src/shared/components/cards/card-app-uptime/card-app-uptime.component.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { Component, OnInit, inject, ChangeDetectionStrategy } from '@angular/core';
22
import { CommonModule } from '@angular/common';
3+
import { RouterLink } from '@angular/router';
34
import { Observable } from 'rxjs';
45
import { map, startWith } from 'rxjs/operators';
56

@@ -18,6 +19,7 @@ import { MetadataItemComponent } from '../../../../../../core/src/shared/compone
1819
standalone: true,
1920
imports: [
2021
CommonModule,
22+
RouterLink,
2123
UptimePipe,
2224
MetadataItemComponent
2325
]

src/frontend/packages/core/src/shared/components/list/list-table/table-row/table-row.component.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
<!-- Main Row -->
1515
<div role="row" class="table-row"
1616
[ngClass]="{'in-expanded-row': !!inExpandedRow, 'has-expanded-row': expandComponent, 'has-error-row': errorMessage$ | async, 'table-row-wrapper__highlighted': isHighlighted$ | async}">
17-
<div class="flex items-start table-row__inner"
17+
<div class="flex items-center table-row__inner"
1818
[ngStyle]="{'min-height': minRowHeight || defaultMinRowHeight }">
1919

2020
<!-- Expander Cell (if expandable) -->

0 commit comments

Comments
 (0)