Skip to content
Open
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
49 changes: 18 additions & 31 deletions src/app/profiles/profile-detail/profile-detail.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -320,24 +320,22 @@
<mat-error>{{ 'profileDetail.connectionModeRequired.value' | translate }}</mat-error>
</p>
}
<fieldset>
<legend>{{ 'profileDetail.internetModeLegend.value' | translate }}</legend>
<p>{{ 'profileDetail.internetModeDescription.value' | translate }}</p>
<p>
<mat-radio-button
data-cy="radio-cira"
[value]="connectionMode.cira"
[disabled]="!ciraEnabled() || ciraConfigurations().length === 0">
{{ 'profileDetail.ciraCloud.value' | translate }}
@if (!ciraEnabled()) {
<span>{{ 'profileDetail.ciraDisabledOption.value' | translate }}</span>
} @else if (ciraConfigurations().length === 0) {
<span>{{ 'profileDetail.noCiraConfigs.value' | translate }}</span>
}
</mat-radio-button>
</p>
@if (profileForm.get('connectionMode')?.value === 'CIRA') {
@if (ciraEnabled()) {
@if (ciraEnabled()) {
<fieldset>
<legend>{{ 'profileDetail.internetModeLegend.value' | translate }}</legend>
<p>{{ 'profileDetail.internetModeDescription.value' | translate }}</p>
<p>
<mat-radio-button
data-cy="radio-cira"
[value]="connectionMode.cira"
[disabled]="ciraConfigurations().length === 0">
Comment thread
nmgaston marked this conversation as resolved.
{{ 'profileDetail.ciraCloud.value' | translate }}
@if (ciraConfigurations().length === 0) {
<span>{{ 'profileDetail.noCiraConfigs.value' | translate }}</span>
}
Comment thread
nmgaston marked this conversation as resolved.
</mat-radio-button>
</p>
@if (profileForm.get('connectionMode')?.value === 'CIRA') {
<mat-form-field class="flex flex-1">
<mat-label>{{ 'profileDetail.ciraConfiguration.value' | translate }}</mat-label>
<mat-select formControlName="ciraConfigName">
Expand All @@ -352,20 +350,9 @@
{{ 'profileDetail.ciraConfigHint.value' | translate }}
</mat-hint>
</mat-form-field>
} @else {
<!-- CIRA disabled on this server but the profile still references a CIRA config.
Show it read-only with a warning and let the user switch to TLS/Direct. -->
<p class="error-messages-container">
<mat-icon color="warn">warning</mat-icon>
<span class="error-messages">{{ 'profileDetail.ciraDisabledWarning.value' | translate }}</span>
</p>
<mat-form-field class="flex flex-1">
<mat-label>{{ 'profileDetail.ciraConfiguration.value' | translate }}</mat-label>
<input matInput formControlName="ciraConfigName" readonly />
</mat-form-field>
}
}
</fieldset>
</fieldset>
}
<fieldset>
<legend>{{ 'profileDetail.directConnectLegend.value' | translate }}</legend>
<p>
Expand Down
37 changes: 33 additions & 4 deletions src/app/profiles/profile-detail/profile-detail.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<ProfileDetailComponent>
let profileSpy: jasmine.Spy
Expand Down Expand Up @@ -148,6 +149,7 @@ describe('ProfileDetailComponent', () => {
})

afterEach(() => {
environment.cloud = defaultCloudMode
TestBed.resetTestingModule()
})

Expand All @@ -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)
Expand All @@ -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)
Expand Down Expand Up @@ -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(() => {
Expand All @@ -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', () => {
Expand All @@ -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', () => {
Expand All @@ -880,6 +908,7 @@ describe('ProfileDetailComponent', () => {

expect(ciraGetDataSpy).toHaveBeenCalled()
expect(enterpriseComponent.ciraEnabled()).toBeTrue()
expect(fixture.nativeElement.querySelector('[data-cy="radio-cira"]')).not.toBeNull()
})
})

Expand Down
25 changes: 24 additions & 1 deletion src/app/profiles/profile-detail/profile-detail.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string[]>([])

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
12 changes: 1 addition & 11 deletions src/app/profiles/profiles.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,7 @@ <h3 class="flex justify-center">{{ 'profiles.noData.value' | translate }}</h3>
<mat-header-cell *matHeaderCellDef style="flex: 1 1 0">
{{ 'profiles.table.name.value' | translate }}
</mat-header-cell>
<mat-cell *matCellDef="let element" style="flex: 1 1 0">
{{ element.profileName }}
@if (!ciraEnabled() && element.ciraConfigName) {
<mat-icon
color="warn"
[matTooltip]="'profileDetail.ciraDisabledWarning.value' | translate"
style="font-size: 18px; height: 18px; width: 18px; vertical-align: middle; margin-left: 4px"
>warning</mat-icon
>
}
</mat-cell>
<mat-cell *matCellDef="let element" style="flex: 1 1 0">{{ element.profileName }}</mat-cell>
</ng-container>
<!-- network config Column -->
<ng-container matColumnDef="networkConfig">
Expand Down
2 changes: 0 additions & 2 deletions src/app/profiles/profiles.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -63,7 +62,6 @@ import { ServerFeaturesService } from '../server-features.service'
MatRowDef,
MatRow,
MatPaginator,
MatTooltip,
ToolkitPipe,
TranslatePipe
]
Expand Down
8 changes: 0 additions & 8 deletions src/assets/i18n/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "تكوين الاتصال المُوفر"
Expand Down
8 changes: 0 additions & 8 deletions src/assets/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
8 changes: 0 additions & 8 deletions src/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
8 changes: 0 additions & 8 deletions src/assets/i18n/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
8 changes: 0 additions & 8 deletions src/assets/i18n/fi.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
8 changes: 0 additions & 8 deletions src/assets/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
8 changes: 0 additions & 8 deletions src/assets/i18n/he.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "תצורת חיבור אספקת"
Expand Down
8 changes: 0 additions & 8 deletions src/assets/i18n/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
8 changes: 0 additions & 8 deletions src/assets/i18n/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -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": "プロビジョニング済み接続設定"
Expand Down
Loading
Loading