diff --git a/src/app/profiles/profile-detail/profile-detail.component.html b/src/app/profiles/profile-detail/profile-detail.component.html index 0ca566f15..09d9bb096 100644 --- a/src/app/profiles/profile-detail/profile-detail.component.html +++ b/src/app/profiles/profile-detail/profile-detail.component.html @@ -320,24 +320,22 @@ {{ 'profileDetail.connectionModeRequired.value' | translate }}

} -
- {{ 'profileDetail.internetModeLegend.value' | translate }} -

{{ 'profileDetail.internetModeDescription.value' | translate }}

-

- - {{ 'profileDetail.ciraCloud.value' | translate }} - @if (!ciraEnabled()) { - {{ 'profileDetail.ciraDisabledOption.value' | translate }} - } @else if (ciraConfigurations().length === 0) { - {{ 'profileDetail.noCiraConfigs.value' | translate }} - } - -

- @if (profileForm.get('connectionMode')?.value === 'CIRA') { - @if (ciraEnabled()) { + @if (ciraEnabled()) { +
+ {{ 'profileDetail.internetModeLegend.value' | translate }} +

{{ 'profileDetail.internetModeDescription.value' | translate }}

+

+ + {{ 'profileDetail.ciraCloud.value' | translate }} + @if (ciraConfigurations().length === 0) { + {{ 'profileDetail.noCiraConfigs.value' | translate }} + } + +

+ @if (profileForm.get('connectionMode')?.value === 'CIRA') { {{ 'profileDetail.ciraConfiguration.value' | translate }} @@ -352,20 +350,9 @@ {{ 'profileDetail.ciraConfigHint.value' | translate }} - } @else { - -

- warning - {{ 'profileDetail.ciraDisabledWarning.value' | translate }} -

- - {{ 'profileDetail.ciraConfiguration.value' | translate }} - - } - } -
+
+ }
{{ 'profileDetail.directConnectLegend.value' | translate }}

diff --git a/src/app/profiles/profile-detail/profile-detail.component.spec.ts b/src/app/profiles/profile-detail/profile-detail.component.spec.ts index e03dde026..85c041f48 100644 --- a/src/app/profiles/profile-detail/profile-detail.component.spec.ts +++ b/src/app/profiles/profile-detail/profile-detail.component.spec.ts @@ -27,6 +27,7 @@ import { provideHttpClientTesting } from '@angular/common/http/testing' import { provideTranslateHttpLoader, TRANSLATE_HTTP_LOADER_CONFIG } from '@ngx-translate/http-loader' describe('ProfileDetailComponent', () => { + const defaultCloudMode = environment.cloud let component: ProfileDetailComponent let fixture: ComponentFixture let profileSpy: jasmine.Spy @@ -148,6 +149,7 @@ describe('ProfileDetailComponent', () => { }) afterEach(() => { + environment.cloud = defaultCloudMode TestBed.resetTestingModule() }) @@ -174,6 +176,7 @@ describe('ProfileDetailComponent', () => { expect(wirelessGetDataSpy).toHaveBeenCalled() expect(proxyGetDataSpy).toHaveBeenCalled() }) + it('should set connectionMode to TLS when tlsMode is a TLS mode (1-4)', () => { const profile: Profile = { tlsMode: 4, ciraConfigName: 'config1' } as any component.setConnectionMode(profile) @@ -184,6 +187,26 @@ describe('ProfileDetailComponent', () => { component.setConnectionMode(profile) expect(component.profileForm.controls.connectionMode.value).toBe('CIRA') }) + it('should not set connectionMode to CIRA when CIRA is disabled and availability is resolved', () => { + component.profileForm.controls.ciraConfigName.setValue('config1') + component.ciraEnabled.set(false) + ;(component as any).ciraAvailabilityResolved.set(true) + + const profile: Profile = { ciraConfigName: 'config1' } as any + component.setConnectionMode(profile) + + expect(component.profileForm.controls.connectionMode.value).toBe('DIRECT') + expect(component.profileForm.controls.ciraConfigName.value).toBeNull() + }) + it('should keep CIRA connectionMode before enterprise feature availability resolves', () => { + component.ciraEnabled.set(false) + ;(component as any).ciraAvailabilityResolved.set(false) + + const profile: Profile = { ciraConfigName: 'config1' } as any + component.setConnectionMode(profile) + + expect(component.profileForm.controls.connectionMode.value).toBe('CIRA') + }) it('should set connectionMode to DIRECT when tlsMode is 0 and no CIRA config', () => { const profile: Profile = { tlsMode: 0, ciraConfigName: null } as any component.setConnectionMode(profile) @@ -835,9 +858,11 @@ describe('ProfileDetailComponent', () => { // server-features branch instead of the cloud branch. const createEnterpriseComponent = (): ProfileDetailComponent => { environment.cloud = false - const enterpriseFixture = TestBed.createComponent(ProfileDetailComponent) - enterpriseFixture.detectChanges() - return enterpriseFixture.componentInstance + fixture.destroy() + fixture = TestBed.createComponent(ProfileDetailComponent) + component = fixture.componentInstance + fixture.detectChanges() + return component } afterEach(() => { @@ -848,10 +873,12 @@ describe('ProfileDetailComponent', () => { serverFeaturesGetFeaturesSpy.and.returnValue(of({ ciraEnabled: false })) ciraGetDataSpy.calls.reset() - createEnterpriseComponent() + const enterpriseComponent = createEnterpriseComponent() expect(serverFeaturesGetFeaturesSpy).toHaveBeenCalled() expect(ciraGetDataSpy).not.toHaveBeenCalled() + expect(enterpriseComponent.ciraEnabled()).toBeFalse() + expect(fixture.nativeElement.querySelector('[data-cy="radio-cira"]')).toBeNull() }) it('should expose ciraEnabled() === false after the features call resolves with CIRA disabled', () => { @@ -870,6 +897,7 @@ describe('ProfileDetailComponent', () => { expect(ciraGetDataSpy).toHaveBeenCalled() expect(enterpriseComponent.ciraEnabled()).toBeTrue() + expect(fixture.nativeElement.querySelector('[data-cy="radio-cira"]')).not.toBeNull() }) it('should fail open and fetch CIRA configs when the features call errors', () => { @@ -880,6 +908,7 @@ describe('ProfileDetailComponent', () => { expect(ciraGetDataSpy).toHaveBeenCalled() expect(enterpriseComponent.ciraEnabled()).toBeTrue() + expect(fixture.nativeElement.querySelector('[data-cy="radio-cira"]')).not.toBeNull() }) }) diff --git a/src/app/profiles/profile-detail/profile-detail.component.ts b/src/app/profiles/profile-detail/profile-detail.component.ts index c61998aaf..18d1610bd 100644 --- a/src/app/profiles/profile-detail/profile-detail.component.ts +++ b/src/app/profiles/profile-detail/profile-detail.component.ts @@ -147,6 +147,9 @@ export class ProfileDetailComponent implements OnInit { // (fetched on init). Start from cloudMode so enterprise hides CIRA until the // API responds, avoiding a flash when the server reports CIRA disabled. public readonly ciraEnabled = signal(this.cloudMode) + // Enterprise starts with ciraEnabled=false before server features return; track + // when availability is actually known to avoid coercing a saved CIRA profile too early. + private readonly ciraAvailabilityResolved = signal(this.cloudMode) public readonly isLoading = signal(false) public readonly errorMessages = signal([]) @@ -217,17 +220,35 @@ export class ProfileDetailComponent implements OnInit { this.serverFeaturesService.getFeatures().subscribe({ next: (features) => { this.ciraEnabled.set(features.ciraEnabled) + this.ciraAvailabilityResolved.set(true) + if (!features.ciraEnabled) { + this.coerceConnectionModeIfCiraUnavailable() + } if (features.ciraEnabled) this.getCiraConfigs() }, // Fail open: if the features call fails, assume CIRA is enabled. error: () => { this.ciraEnabled.set(true) + this.ciraAvailabilityResolved.set(true) this.getCiraConfigs() } }) } } + private coerceConnectionModeIfCiraUnavailable(): void { + if (this.profileForm.controls.connectionMode.value !== this.connectionMode.cira) { + return + } + + // Keep existing TLS profiles on TLS; otherwise fall back to DIRECT. + const fallbackMode = + this.profileForm.controls.tlsMode.value != null && this.profileForm.controls.tlsMode.value > 0 + ? this.connectionMode.tls + : this.connectionMode.direct + this.profileForm.controls.connectionMode.setValue(fallbackMode) + } + private setupFormSubscriptions(): void { this.profileForm.controls.activation.valueChanges.subscribe((value) => { if (value) this.activationChange(value) @@ -262,9 +283,11 @@ export class ProfileDetailComponent implements OnInit { } setConnectionMode(data: Profile): void { + const canUseCira = this.ciraEnabled() || !this.ciraAvailabilityResolved() + if (data.tlsMode != null && data.tlsMode > 0) { this.profileForm.controls.connectionMode.setValue(this.connectionMode.tls) - } else if (data.ciraConfigName != null) { + } else if (data.ciraConfigName != null && canUseCira) { this.profileForm.controls.connectionMode.setValue(this.connectionMode.cira) } else { this.profileForm.controls.connectionMode.setValue(this.connectionMode.direct) diff --git a/src/app/profiles/profiles.component.html b/src/app/profiles/profiles.component.html index fa24491b2..13576233d 100644 --- a/src/app/profiles/profiles.component.html +++ b/src/app/profiles/profiles.component.html @@ -24,17 +24,7 @@

{{ 'profiles.noData.value' | translate }}

{{ 'profiles.table.name.value' | translate }} - - {{ element.profileName }} - @if (!ciraEnabled() && element.ciraConfigName) { - warning - } - + {{ element.profileName }} diff --git a/src/app/profiles/profiles.component.ts b/src/app/profiles/profiles.component.ts index 24cc02ce0..d3247e212 100644 --- a/src/app/profiles/profiles.component.ts +++ b/src/app/profiles/profiles.component.ts @@ -33,7 +33,6 @@ import { MatProgressBar } from '@angular/material/progress-bar' import { MatIcon } from '@angular/material/icon' import { MatButton, MatIconButton } from '@angular/material/button' import { MatToolbar } from '@angular/material/toolbar' -import { MatTooltip } from '@angular/material/tooltip' import { environment } from '../../environments/environment' import { KeyDisplayDialogComponent } from './key-display-dialog/key-display-dialog.component' import { TranslatePipe, TranslateService } from '@ngx-translate/core' @@ -63,7 +62,6 @@ import { ServerFeaturesService } from '../server-features.service' MatRowDef, MatRow, MatPaginator, - MatTooltip, ToolkitPipe, TranslatePipe ] diff --git a/src/assets/i18n/ar.json b/src/assets/i18n/ar.json index 57c85e7f4..d9b002647 100644 --- a/src/assets/i18n/ar.json +++ b/src/assets/i18n/ar.json @@ -2149,14 +2149,6 @@ "description": "تسمية حقل تكوين CIRA", "value": "تكوين CIRA" }, - "profileDetail.ciraDisabledOption": { - "description": "Inline note on the CIRA radio when CIRA is disabled on the server", - "value": "(CIRA معطّل على هذا الخادم)" - }, - "profileDetail.ciraDisabledWarning": { - "description": "Warning shown when editing a profile that uses CIRA while CIRA is disabled on the server", - "value": "CIRA معطّل على هذا الخادم. يستخدم هذا الملف الشخصي CIRA لاتصال الإدارة الخاص به ولن يعمل حتى تتم إعادة تمكين CIRA." - }, "profileDetail.connectionConfiguration": { "description": "تسمية قسم تكوين الاتصال", "value": "تكوين الاتصال المُوفر" diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index bc84346e9..25732e517 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -2149,14 +2149,6 @@ "description": "Bezeichnung für das CIRA-Konfigurationsfeld", "value": "CIRA-Konfiguration" }, - "profileDetail.ciraDisabledOption": { - "description": "Inline note on the CIRA radio when CIRA is disabled on the server", - "value": "(CIRA ist auf diesem Server deaktiviert)" - }, - "profileDetail.ciraDisabledWarning": { - "description": "Warning shown when editing a profile that uses CIRA while CIRA is disabled on the server", - "value": "CIRA ist auf diesem Server deaktiviert. Dieses Profil verwendet CIRA für seine Verwaltungsverbindung und funktioniert erst, wenn CIRA wieder aktiviert wird." - }, "profileDetail.connectionConfiguration": { "description": "Bezeichnung für den Abschnitt zur Verbindungskonfiguration", "value": "Konfiguration der bereitgestellten Verbindung" diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 5830a8654..594a0356f 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -2619,14 +2619,6 @@ "description": "Label for CIRA configuration field", "value": "CIRA Configuration" }, - "profileDetail.ciraDisabledOption": { - "description": "Inline note on the CIRA radio when CIRA is disabled on the server", - "value": "(CIRA is disabled on this server)" - }, - "profileDetail.ciraDisabledWarning": { - "description": "Warning shown when editing a profile that uses CIRA while CIRA is disabled on the server", - "value": "CIRA is disabled on this server. This profile uses CIRA for its management connection and won't work until CIRA is re-enabled." - }, "profileDetail.connectionConfiguration": { "description": "Label for connection configuration section", "value": "Provisioned Connection Configuration" diff --git a/src/assets/i18n/es.json b/src/assets/i18n/es.json index 4a5583b57..705c0943e 100644 --- a/src/assets/i18n/es.json +++ b/src/assets/i18n/es.json @@ -2149,14 +2149,6 @@ "description": "Etiqueta para el campo de configuración CIRA.", "value": "Configuración de CIRA" }, - "profileDetail.ciraDisabledOption": { - "description": "Inline note on the CIRA radio when CIRA is disabled on the server", - "value": "(CIRA está deshabilitado en este servidor)" - }, - "profileDetail.ciraDisabledWarning": { - "description": "Warning shown when editing a profile that uses CIRA while CIRA is disabled on the server", - "value": "CIRA está deshabilitado en este servidor. Este perfil usa CIRA para su conexión de administración y no funcionará hasta que se vuelva a habilitar CIRA." - }, "profileDetail.connectionConfiguration": { "description": "Etiqueta para la sección de configuración de la conexión.", "value": "Configuración de la conexión aprovisionada" diff --git a/src/assets/i18n/fi.json b/src/assets/i18n/fi.json index 2aeabbdbc..495987c85 100644 --- a/src/assets/i18n/fi.json +++ b/src/assets/i18n/fi.json @@ -2149,14 +2149,6 @@ "description": "CIRA-määrityskentän nimi", "value": "CIRA-konfiguraatio" }, - "profileDetail.ciraDisabledOption": { - "description": "Inline note on the CIRA radio when CIRA is disabled on the server", - "value": "(CIRA on poistettu käytöstä tällä palvelimella)" - }, - "profileDetail.ciraDisabledWarning": { - "description": "Warning shown when editing a profile that uses CIRA while CIRA is disabled on the server", - "value": "CIRA on poistettu käytöstä tällä palvelimella. Tämä profiili käyttää CIRAa hallintayhteyteensä eikä toimi, ennen kuin CIRA otetaan uudelleen käyttöön." - }, "profileDetail.connectionConfiguration": { "description": "Yhteysasetusten osion nimike", "value": "Provisioitu yhteyden konfigurointi" diff --git a/src/assets/i18n/fr.json b/src/assets/i18n/fr.json index fbe4a1230..a3c7bfbf0 100644 --- a/src/assets/i18n/fr.json +++ b/src/assets/i18n/fr.json @@ -2149,14 +2149,6 @@ "description": "Étiquette pour le champ de configuration CIRA", "value": "Configuration CIRA" }, - "profileDetail.ciraDisabledOption": { - "description": "Inline note on the CIRA radio when CIRA is disabled on the server", - "value": "(CIRA est désactivé sur ce serveur)" - }, - "profileDetail.ciraDisabledWarning": { - "description": "Warning shown when editing a profile that uses CIRA while CIRA is disabled on the server", - "value": "CIRA est désactivé sur ce serveur. Ce profil utilise CIRA pour sa connexion de gestion et ne fonctionnera pas tant que CIRA n'est pas réactivé." - }, "profileDetail.connectionConfiguration": { "description": "Étiquette pour la section de configuration de la connexion", "value": "Configuration de la connexion provisionnée" diff --git a/src/assets/i18n/he.json b/src/assets/i18n/he.json index 6315ca2cb..9329b0195 100644 --- a/src/assets/i18n/he.json +++ b/src/assets/i18n/he.json @@ -2149,14 +2149,6 @@ "description": "תווית לשדה תצורת CIRA", "value": "תצורת CIRA" }, - "profileDetail.ciraDisabledOption": { - "description": "Inline note on the CIRA radio when CIRA is disabled on the server", - "value": "(CIRA מושבת בשרת זה)" - }, - "profileDetail.ciraDisabledWarning": { - "description": "Warning shown when editing a profile that uses CIRA while CIRA is disabled on the server", - "value": "CIRA מושבת בשרת זה. פרופיל זה משתמש ב-CIRA לחיבור הניהול שלו ולא יעבוד עד ש-CIRA יופעל מחדש." - }, "profileDetail.connectionConfiguration": { "description": "תווית לקטע תצורת חיבור", "value": "תצורת חיבור אספקת" diff --git a/src/assets/i18n/it.json b/src/assets/i18n/it.json index 398e4c77d..137d3d4df 100644 --- a/src/assets/i18n/it.json +++ b/src/assets/i18n/it.json @@ -2149,14 +2149,6 @@ "description": "Etichetta per il campo di configurazione CIRA", "value": "Configurazione CIRA" }, - "profileDetail.ciraDisabledOption": { - "description": "Inline note on the CIRA radio when CIRA is disabled on the server", - "value": "(CIRA è disabilitato su questo server)" - }, - "profileDetail.ciraDisabledWarning": { - "description": "Warning shown when editing a profile that uses CIRA while CIRA is disabled on the server", - "value": "CIRA è disabilitato su questo server. Questo profilo utilizza CIRA per la sua connessione di gestione e non funzionerà finché CIRA non viene riabilitato." - }, "profileDetail.connectionConfiguration": { "description": "Etichetta per la sezione di configurazione della connessione", "value": "Configurazione della connessione fornita" diff --git a/src/assets/i18n/ja.json b/src/assets/i18n/ja.json index c85d85cd0..a0e6327d6 100644 --- a/src/assets/i18n/ja.json +++ b/src/assets/i18n/ja.json @@ -2149,14 +2149,6 @@ "description": "CIRA設定フィールドのラベル", "value": "CIRA設定" }, - "profileDetail.ciraDisabledOption": { - "description": "Inline note on the CIRA radio when CIRA is disabled on the server", - "value": "(このサーバーでは CIRA が無効になっています)" - }, - "profileDetail.ciraDisabledWarning": { - "description": "Warning shown when editing a profile that uses CIRA while CIRA is disabled on the server", - "value": "このサーバーでは CIRA が無効になっています。このプロファイルは管理接続に CIRA を使用しているため、CIRA が再度有効になるまで機能しません。" - }, "profileDetail.connectionConfiguration": { "description": "接続設定セクションのラベル", "value": "プロビジョニング済み接続設定" diff --git a/src/assets/i18n/nl.json b/src/assets/i18n/nl.json index f5a255335..5eb9030e4 100644 --- a/src/assets/i18n/nl.json +++ b/src/assets/i18n/nl.json @@ -2149,14 +2149,6 @@ "description": "Label voor CIRA-configuratieveld", "value": "CIRA-configuratie" }, - "profileDetail.ciraDisabledOption": { - "description": "Inline note on the CIRA radio when CIRA is disabled on the server", - "value": "(CIRA is uitgeschakeld op deze server)" - }, - "profileDetail.ciraDisabledWarning": { - "description": "Warning shown when editing a profile that uses CIRA while CIRA is disabled on the server", - "value": "CIRA is uitgeschakeld op deze server. Dit profiel gebruikt CIRA voor zijn beheerverbinding en werkt pas als CIRA opnieuw is ingeschakeld." - }, "profileDetail.connectionConfiguration": { "description": "Label voor het gedeelte over verbindingsconfiguratie", "value": "Configuratie van de geleverde verbinding" diff --git a/src/assets/i18n/ru.json b/src/assets/i18n/ru.json index 15c59a596..a6e339dae 100644 --- a/src/assets/i18n/ru.json +++ b/src/assets/i18n/ru.json @@ -2149,14 +2149,6 @@ "description": "Метка для поля конфигурации CIRA", "value": "Конфигурация CIRA" }, - "profileDetail.ciraDisabledOption": { - "description": "Inline note on the CIRA radio when CIRA is disabled on the server", - "value": "(CIRA отключён на этом сервере)" - }, - "profileDetail.ciraDisabledWarning": { - "description": "Warning shown when editing a profile that uses CIRA while CIRA is disabled on the server", - "value": "CIRA отключён на этом сервере. Этот профиль использует CIRA для подключения управления и не будет работать, пока CIRA не будет снова включён." - }, "profileDetail.connectionConfiguration": { "description": "Метка для раздела настройки подключения", "value": "Настройка предоставленного соединения" diff --git a/src/assets/i18n/sv.json b/src/assets/i18n/sv.json index b76e46eee..1eca64cb9 100644 --- a/src/assets/i18n/sv.json +++ b/src/assets/i18n/sv.json @@ -2149,14 +2149,6 @@ "description": "Etikett för CIRA-konfigurationsfält", "value": "CIRA-konfiguration" }, - "profileDetail.ciraDisabledOption": { - "description": "Inline note on the CIRA radio when CIRA is disabled on the server", - "value": "(CIRA är inaktiverat på den här servern)" - }, - "profileDetail.ciraDisabledWarning": { - "description": "Warning shown when editing a profile that uses CIRA while CIRA is disabled on the server", - "value": "CIRA är inaktiverat på den här servern. Den här profilen använder CIRA för sin hanteringsanslutning och fungerar inte förrän CIRA återaktiveras." - }, "profileDetail.connectionConfiguration": { "description": "Etikett för avsnittet om anslutningskonfiguration", "value": "Konfiguration av tillhandahållen anslutning"