Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions changelog.d/0021-rxjs7-deprecations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[BugFixes]
- The application log stream tab now stops after three failed
connection attempts instead of opening a fourth connection and
closing it at once, and it starts counting again after a successful
connection. Before, a stream that connected and later dropped could
stop reconnecting.
- The application log stream tab now says when it is retrying the
connection (with the attempt number) and when it has given up,
instead of showing "Connecting to log stream..." for good.

[Maintainability]
- Replaced the RxJS APIs deprecated in RxJS 7 (publishReplay/refCount,
retryWhen, toPromise, multi-argument combineLatest and subscribe,
the combineLatest operator, throwError with a value), the deprecated
HttpClientModule, and the NgZone wrappers that do nothing in the
zoneless app. Lint rules now reject them, and the theme package is
linted.
49 changes: 49 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,55 @@ export default tseslint.config(
// A snackbar service injected but never called is dead weight that
// misleads readers about what the component can do (#5603).
"stratos/no-unused-snackbar-service": "error",

// APIs deprecated in RxJS 7 (removed in RxJS 8) and Angular APIs the
// zoneless app has no use for. All call sites were replaced in #6022;
// these keep them from coming back.
"no-restricted-imports": ["error", { paths: [
...["rxjs", "rxjs/operators"].map(name => ({
name,
importNames: ["publishReplay", "refCount", "publish", "publishLast", "publishBehavior", "multicast"],
message: "Deprecated in RxJS 7: use shareReplay({ bufferSize: 1, refCount: true }), share() or connectable().",
})),
...["rxjs", "rxjs/operators"].map(name => ({
name,
importNames: ["retryWhen"],
message: "Deprecated in RxJS 7: use retry({ count, delay }).",
})),
{
name: "rxjs/operators",
importNames: ["combineLatest"],
message: "Deprecated in RxJS 7: use the combineLatestWith operator.",
},
{
name: "@angular/common/http",
importNames: ["HttpClientModule"],
message: "Deprecated: the app configures HttpClient with provideHttpClient() in AppModule.",
},
{
name: "@angular/core",
importNames: ["NgZone"],
message: "The app is zoneless: NgZone.run() and runOutsideAngular() only call their callback.",
},
] }],
"no-restricted-syntax": ["error",
{
selector: "CallExpression[callee.property.name='toPromise']",
message: "Deprecated in RxJS 7: use firstValueFrom() or lastValueFrom().",
},
{
selector: "CallExpression[callee.property.name='subscribe'][arguments.length>1]",
message: "Deprecated in RxJS 7: pass one observer, subscribe({ next, error, complete }).",
},
{
selector: "CallExpression[callee.name=/^(combineLatest|observableCombineLatest)$/][arguments.length>1]",
message: "Deprecated in RxJS 7: pass the sources as one array, combineLatest([a, b]).",
},
{
selector: "CallExpression[callee.name='throwError'][arguments.0.type!=/^(ArrowFunctionExpression|FunctionExpression)$/]",
message: "Deprecated in RxJS 7: pass an inline error factory, throwError(() => error).",
},
],
},
},
{
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"test-frontend:kubernetes": "vitest run --project=kubernetes",
"test-frontend:git": "vitest run --project=git",
"posttest": "echo 'Coverage reports in coverage/frontend/ directory'",
"lint": "eslint --report-unused-disable-directives-severity warn src/frontend/packages/{core,store,cloud-foundry,kubernetes,cf-autoscaler,git,shared,extension}/src/ e2e/ && bun test --config=scripts/tests/bunfig.toml tools/eslint-rules/tests scripts/tests && bun scripts/lint-e2e-data-test.mjs && bun scripts/lint-e2e-ratchet.mjs && bun scripts/lint-nested-pins.mjs",
"lint": "eslint --report-unused-disable-directives-severity warn src/frontend/packages/{core,store,cloud-foundry,kubernetes,cf-autoscaler,git,shared,extension}/src/ src/frontend/packages/theme/ e2e/ && bun test --config=scripts/tests/bunfig.toml tools/eslint-rules/tests scripts/tests && bun scripts/lint-e2e-data-test.mjs && bun scripts/lint-e2e-ratchet.mjs && bun scripts/lint-nested-pins.mjs",
"lint:docs": "bun scripts/lint-docs.mjs",
"e2e": "playwright test",
"e2e:ui": "playwright test --ui",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, WritableSignal, computed, inject, signal } from '@angular/core';
import { RouterModule } from '@angular/router';
import { Observable } from 'rxjs';
import { map, publishReplay, refCount } from 'rxjs/operators';
import { map, shareReplay } from 'rxjs/operators';

import { ApplicationService } from '../../../../cloud-foundry/src/features/applications/application.service';
import { CustomIconComponent, SignalListComponent, SignalListConfig } from '@stratosui/core';
Expand Down Expand Up @@ -94,8 +94,7 @@ export class AutoscalerMetricPageComponent implements OnInit {
ngOnInit() {
this.applicationName$ = this.applicationService.app$.pipe(
map(({ entity }) => entity ? entity.entity.name : null),
publishReplay(1),
refCount()
shareReplay({ bufferSize: 1, refCount: true })
);
void this.chartConfig.loadAll();
this.cdr.markForCheck();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, Writable
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { Observable } from 'rxjs';
import { map, publishReplay, refCount } from 'rxjs/operators';
import { map, shareReplay } from 'rxjs/operators';

import { ApplicationService } from '@stratosui/cloud-foundry';
import { CustomIconComponent, PageHeaderModule, SignalListComponent, SignalListConfig, SignalListPillColor } from '@stratosui/core';
Expand Down Expand Up @@ -102,8 +102,7 @@ export class AutoscalerScaleHistoryPageComponent implements OnInit {
ngOnInit() {
this.applicationName$ = this.applicationService.app$.pipe(
map(({ entity }) => entity ? entity.entity.name : null),
publishReplay(1),
refCount()
shareReplay({ bufferSize: 1, refCount: true })
);
void this.eventsConfig.loadAll();
this.cdr.markForCheck();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
import { ActivatedRoute, Router, RouterModule } from '@angular/router';
import { ErrorStateMatcher, ShowOnDirtyErrorStateMatcher } from '@stratosui/core';
import { Observable, Subscription, firstValueFrom } from 'rxjs';
import { map, publishReplay, refCount } from 'rxjs/operators';
import { map, shareReplay } from 'rxjs/operators';

import { ApplicationService } from '@stratosui/cloud-foundry';
import {
Expand Down Expand Up @@ -215,8 +215,7 @@ export class EditAutoscalerPolicyComponent implements OnInit, OnDestroy {
ngOnInit() {
this.applicationName$ = this.applicationService.app$.pipe(
map(({ entity }) => entity ? entity.entity.name : null),
publishReplay(1),
refCount()
shareReplay({ bufferSize: 1, refCount: true })
);
this.isCreate = this.route.snapshot.queryParams.create;
this.cdr.markForCheck();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { CommonModule } from '@angular/common';
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, ElementRef, Injector, Input, OnInit, ViewChild, computed, inject } from '@angular/core';
import { toObservable } from '@angular/core/rxjs-interop';
import { Observable } from 'rxjs';
import { map, publishReplay, refCount } from 'rxjs/operators';
import { map, shareReplay } from 'rxjs/operators';

import { ApplicationService, RunningInstancesComponent } from '@stratosui/cloud-foundry';
import { MetadataItemComponent } from '@stratosui/core';
Expand Down Expand Up @@ -66,14 +66,12 @@ export class CardAutoscalerDefaultComponent implements OnInit {
});

this.appAutoscalerPolicy$ = toObservable(triState, { injector: this.injector }).pipe(
publishReplay(1),
refCount(),
shareReplay({ bufferSize: 1, refCount: true }),
);

this.applicationInstances$ = this.applicationService.app$.pipe(
map(({ entity }) => entity ? entity.entity.instances : null),
publishReplay(1),
refCount()
shareReplay({ bufferSize: 1, refCount: true })
);
this.cdr.markForCheck();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { StRoute, StServiceCredentialBinding } from '../../services/endpoin
* Resolved display names the wizard already had on hand when the user
* pressed Confirm. The parent's "Are you sure?" dialog uses these
* directly instead of racing the data service's observables — by the
* time the parent is recreated post-navigation, its publishReplay
* time the parent is recreated post-navigation, its shareReplay
* caches are gone with the old instance, so the race loses and the
* dialog renders appGuid + "?" for org/space.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Injectable, computed, inject } from '@angular/core';
import { toObservable } from '@angular/core/rxjs-interop';
import { Observable, of as observableOf } from 'rxjs';
import { filter, publishReplay, refCount } from 'rxjs/operators';
import { filter, shareReplay } from 'rxjs/operators';

import { APP_GUID, CF_GUID } from '@stratosui/core';
import {
Expand Down Expand Up @@ -68,8 +68,7 @@ export class ApplicationService {
*/
waitForAppEntity$: Observable<EntityInfo<APIResource<IApp>>> = this.app$.pipe(
filter(info => !!info.entity),
publishReplay(1),
refCount(),
shareReplay({ bufferSize: 1, refCount: true }),
);

/**
Expand Down Expand Up @@ -178,8 +177,7 @@ export class ApplicationService {
})
).pipe(
filter(data => !!data.app),
publishReplay(1),
refCount(),
shareReplay({ bufferSize: 1, refCount: true }),
);

// ---------------------------------------------------------------------------
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CommonModule } from '@angular/common';
import { Component, EffectRef, Injector, NgZone, OnDestroy, OnInit, ChangeDetectionStrategy, effect, inject, runInInjectionContext, signal } from '@angular/core';
import { Component, EffectRef, Injector, OnDestroy, OnInit, ChangeDetectionStrategy, effect, inject, runInInjectionContext, signal } from '@angular/core';
import { toObservable } from '@angular/core/rxjs-interop';
import { Router, RouterModule } from '@angular/router';
import { GitSCMService, GitSCMType } from '@stratosui/git';
Expand Down Expand Up @@ -62,7 +62,6 @@ export class ApplicationTabsBaseComponent implements OnInit, OnDestroy {
applicationService = inject(ApplicationService);
private router = inject(Router);
private endpointsService = inject(EndpointsService);
private ngZone = inject(NgZone);
private currentUserPermissionsService = inject(CurrentUserPermissionsService);
private userFavoriteManager = inject(UserFavoriteManager);
private cfEndpoints = inject(CfEndpointsDataService);
Expand Down Expand Up @@ -318,10 +317,10 @@ export class ApplicationTabsBaseComponent implements OnInit, OnDestroy {
// snackbar convey the action's progress/result in place. Gating on "app
// not yet present" stops those refreshes from blanking the whole page with
// the spinner (the restage repaint regression).
this.isFetching$ = observableCombineLatest(
this.isFetching$ = observableCombineLatest([
this.applicationService.isFetchingApp$,
toObservable(this.detail.app, { injector: this.injector }),
).pipe(
]).pipe(
map(([isFetchingApp, app]) => isFetchingApp && !app),
);

Expand All @@ -330,19 +329,19 @@ export class ApplicationTabsBaseComponent implements OnInit, OnDestroy {
startWith({ updating: true }),
);

const initialFetch$ = observableCombineLatest(
const initialFetch$ = observableCombineLatest([
this.applicationService.isFetchingApp$,
this.applicationService.isFetchingEnvVars$,
this.applicationService.isFetchingStats$
).pipe(
]).pipe(
map(([isFetchingApp, isFetchingEnvVars, isFetchingStats]) => {
return isFetchingApp || isFetchingEnvVars || isFetchingStats;
}));

this.summaryDataChanging$ = observableCombineLatest(
this.summaryDataChanging$ = observableCombineLatest([
initialFetch$,
this.applicationService.isUpdatingApp$,
).pipe(map(([isFetchingApp, isUpdating]) => {
]).pipe(map(([isFetchingApp, isUpdating]) => {
return !!(isFetchingApp || isUpdating);
}));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Component, OnInit, ChangeDetectionStrategy, inject } from '@angular/cor
import { RouterModule } from '@angular/router';
import { GitCommit, GitDataService, GitResourceState, GitRepo, GitSCMService, GitSCMType, SCMIcon } from '@stratosui/git';
import { combineLatest as observableCombineLatest, EMPTY, Observable, of } from 'rxjs';
import { catchError, combineLatest, distinct, distinctUntilChanged, map, startWith, switchMap } from 'rxjs/operators';
import { catchError, combineLatestWith, distinct, distinctUntilChanged, map, startWith, switchMap } from 'rxjs/operators';

import {
CurrentUserPermissionsService,
Expand Down Expand Up @@ -118,15 +118,15 @@ export class BuildTabComponent implements OnInit {
void this.data.refresh('serviceBindings');

this.cardTwoFetching$ = this.applicationService.application$.pipe(
combineLatest(
combineLatestWith(
this.applicationService.appSummary$
),
map(([app, appSummary]: [ApplicationData, EntityInfo<IAppSummary>]) => {
return app.fetching || appSummary.entityRequestInfo.fetching;
}), distinct());

this.sshStatus$ = this.applicationService.application$.pipe(
combineLatest(this.applicationService.appSpace$),
combineLatestWith(this.applicationService.appSpace$),
map(([app, space]) => {
if (!space?.allowSsh) {
return 'Disabled by the space';
Expand Down Expand Up @@ -159,10 +159,10 @@ export class BuildTabComponent implements OnInit {
switchMap(repoResource => repoResource.waitForValue$.pipe(catchError(() => EMPTY)))
);

const deploySource$ = observableCombineLatest(
const deploySource$ = observableCombineLatest([
this.applicationService.applicationStratProject$,
this.applicationService.application$
).pipe(
]).pipe(
map(([project, app]): DeploySourceView | null => {
if (project) {
const deploySource: CustomEnvVarStratosProjectSource = { ...project.deploySource };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
[filter]="filter"
class="app-logstream-viewer flex flex-1 min-h-0"
[logStream]="messages"
[status]="connectionStatus"></app-log-viewer>
[status]="connectionStatus"
[maxReconnectAttempts]="maxRetries - 1"></app-log-viewer>
</div>
Loading
Loading