diff --git a/src/app/core/navbar/navbar.component.ts b/src/app/core/navbar/navbar.component.ts index 63cd109fa..f0bd52c1f 100644 --- a/src/app/core/navbar/navbar.component.ts +++ b/src/app/core/navbar/navbar.component.ts @@ -6,12 +6,13 @@ import { Component, OnInit, inject, signal } from '@angular/core' import { environment } from '../../../environments/environment' import { MatIcon } from '@angular/material/icon' -import { RouterLink, RouterLinkActive } from '@angular/router' +import { NavigationEnd, Router, RouterLink, RouterLinkActive } from '@angular/router' import { MatDivider } from '@angular/material/divider' import { MatNavList, MatListItem, MatListItemIcon } from '@angular/material/list' import { MatTooltip } from '@angular/material/tooltip' import { TranslatePipe, TranslateService } from '@ngx-translate/core' import { ServerFeaturesService } from '../../server-features.service' +import { filter } from 'rxjs/operators' @Component({ selector: 'app-navbar', @@ -37,19 +38,29 @@ export class NavbarComponent implements OnInit { // Start from cloudMode so enterprise hides the tab until the API responds, // avoiding a flash of the tab when the server reports CIRA disabled. ciraEnabled = signal(this.cloudMode) + private readonly router = inject(Router) private readonly translate = inject(TranslateService) private readonly serverFeaturesService = inject(ServerFeaturesService) ngOnInit(): void { if (this.cloudMode === false) { - this.serverFeaturesService.getFeatures().subscribe({ - next: (features) => this.ciraEnabled.set(features.ciraEnabled), - // Fail open: if the features call fails, keep the CIRA tab visible. - error: () => this.ciraEnabled.set(true) + this.refreshCiraAvailability() + // Re-check server feature flags on navigation so runtime server setting + // changes (like enabling CIRA) are reflected without full page reload. + this.router.events.pipe(filter((event) => event instanceof NavigationEnd)).subscribe(() => { + this.refreshCiraAvailability() }) } } + private refreshCiraAvailability(): void { + this.serverFeaturesService.getFeatures().subscribe({ + next: (features) => this.ciraEnabled.set(features.ciraEnabled), + // Fail open: if the features call fails, keep the CIRA tab visible. + error: () => this.ciraEnabled.set(true) + }) + } + get ciraTitle(): string { return this.ciraEnabled() ? this.translate.instant('configs.header.ciraTitle.value') 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..e5c87c720 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('TLS') + 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..6dee36af9 100644 --- a/src/app/profiles/profile-detail/profile-detail.component.ts +++ b/src/app/profiles/profile-detail/profile-detail.component.ts @@ -8,8 +8,8 @@ import { FormBuilder, FormControl, Validators, ReactiveFormsModule } from '@angu import { MatSnackBar } from '@angular/material/snack-bar' import { MatDialog, MatDialogConfig } from '@angular/material/dialog' import { ActivatedRoute, Router } from '@angular/router' -import { finalize, map, startWith } from 'rxjs/operators' -import { forkJoin, Observable } from 'rxjs' +import { concatMap, finalize, map, startWith, takeWhile, toArray } from 'rxjs/operators' +import { from, Observable } from 'rxjs' import { COMMA, ENTER } from '@angular/cdk/keycodes' import { CdkDragDrop, moveItemInArray, CdkDropList, CdkDrag } from '@angular/cdk/drag-drop' import { NgClass, AsyncPipe } from '@angular/common' @@ -44,6 +44,7 @@ import { ServerFeaturesService } from '../../server-features.service' // Shared components import { RandomPassAlertComponent } from '../../shared/random-pass-alert/random-pass-alert.component' import { StaticCIRAWarningComponent } from '../../shared/static-cira-warning/static-cira-warning.component' +import { NoCIRAWarningComponent } from '../../shared/no-cira-warning/no-cira-warning.component' // Models and constants import { CIRAConfig, IEEE8021xConfig } from '../../../models/models' @@ -147,6 +148,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 +221,31 @@ 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 + } + + // CIRA is unavailable, so prefer secure direct TLS over unsecured DIRECT. + this.profileForm.controls.connectionMode.setValue(this.connectionMode.tls) + } + private setupFormSubscriptions(): void { this.profileForm.controls.activation.valueChanges.subscribe((value) => { if (value) this.activationChange(value) @@ -262,10 +280,15 @@ 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 if (data.ciraConfigName != null && !canUseCira) { + // Existing CIRA profiles should default to TLS when CIRA is disabled. + this.profileForm.controls.connectionMode.setValue(this.connectionMode.tls) } else { this.profileForm.controls.connectionMode.setValue(this.connectionMode.direct) } @@ -660,6 +683,11 @@ export class ProfileDetailComponent implements OnInit { return dialog.afterClosed() } + private noCIRAWarning(): Observable { + const dialog = this.dialog.open(NoCIRAWarningComponent, { width: '750px' }) + return dialog.afterClosed() + } + private randPasswordWarning(): Observable { const dialog = this.dialog.open(RandomPassAlertComponent, this.matDialogConfig) return dialog.afterClosed() @@ -670,23 +698,32 @@ export class ProfileDetailComponent implements OnInit { // Warn user of risk if CIRA configuration and static network are selected simultaneously if (this.profileForm.valid) { const result: any = Object.assign({}, this.profileForm.getRawValue()) - const dialogs = [] - if (!this.isEdit() && (result.generateRandomPassword || result.generateRandomMEBxPassword)) { - dialogs.push(this.randPasswordWarning()) + const dialogs: (() => Observable)[] = [] + if (result.connectionMode !== this.connectionMode.cira) { + dialogs.push(() => this.noCIRAWarning()) } if (result.connectionMode === this.connectionMode.cira && result.dhcpEnabled === false) { - dialogs.push(this.CIRAStaticWarning()) + dialogs.push(() => this.CIRAStaticWarning()) + } + if (!this.isEdit() && (result.generateRandomPassword || result.generateRandomMEBxPassword)) { + dialogs.push(() => this.randPasswordWarning()) } if (dialogs.length === 0) { this.onSubmit() return } - forkJoin(dialogs).subscribe((data) => { - if (data.every((x) => x === true)) { - this.onSubmit() - } - }) + from(dialogs) + .pipe( + concatMap((factory) => factory()), + takeWhile((result) => result === true), + toArray() + ) + .subscribe((results) => { + if (results.length === dialogs.length) { + this.onSubmit() + } + }) } else { this.profileForm.markAllAsTouched() } diff --git a/src/app/profiles/profiles.component.html b/src/app/profiles/profiles.component.html index fa24491b2..503f13295 100644 --- a/src/app/profiles/profiles.component.html +++ b/src/app/profiles/profiles.component.html @@ -29,7 +29,15 @@

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

@if (!ciraEnabled() && element.ciraConfigName) { warning + } + @if (!ciraEnabled() && !element.ciraConfigName && !element.tlsMode) { + warning diff --git a/src/app/profiles/profiles.component.spec.ts b/src/app/profiles/profiles.component.spec.ts index a708117f4..1ee29f89e 100644 --- a/src/app/profiles/profiles.component.spec.ts +++ b/src/app/profiles/profiles.component.spec.ts @@ -5,6 +5,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing' import { MatDialog } from '@angular/material/dialog' +import { By } from '@angular/platform-browser' import { BrowserAnimationsModule } from '@angular/platform-browser/animations' import { of } from 'rxjs' @@ -166,4 +167,21 @@ describe('ProfilesComponent', () => { ;(environment as { cloud: boolean }).cloud = originalCloud } }) + + it('should show warning icon on profiles that use CIRA when CIRA is disabled', () => { + component.ciraEnabled.set(false) + fixture.detectChanges() + + const icons = fixture.debugElement.queryAll(By.css('mat-icon[color="warn"]')) + // The mock data has one profile with ciraConfigName set + expect(icons.length).toBe(1) + }) + + it('should not show warning icon when CIRA is enabled', () => { + // ciraEnabled is true by default in cloud mode + fixture.detectChanges() + + const icons = fixture.debugElement.queryAll(By.css('mat-icon[color="warn"]')) + expect(icons.length).toBe(0) + }) }) diff --git a/src/app/shared/no-cira-warning/no-cira-warning.component.html b/src/app/shared/no-cira-warning/no-cira-warning.component.html new file mode 100644 index 000000000..6521263f6 --- /dev/null +++ b/src/app/shared/no-cira-warning/no-cira-warning.component.html @@ -0,0 +1,16 @@ + +

+ warning + {{ 'noCira.title.value' | translate }} +

+ +

{{ 'noCira.message.value' | translate }}

+

{{ 'noCira.hint.value' | translate }}

+

{{ 'noCira.confirm.value' | translate }}

+
+ + + + diff --git a/src/app/shared/no-cira-warning/no-cira-warning.component.scss b/src/app/shared/no-cira-warning/no-cira-warning.component.scss new file mode 100644 index 000000000..cb12928b5 --- /dev/null +++ b/src/app/shared/no-cira-warning/no-cira-warning.component.scss @@ -0,0 +1,23 @@ +.dialog-top-spacer { + height: 20px; +} + +h2[mat-dialog-title] { + display: flex; + align-items: center; + gap: 8px; +} + +mat-dialog-content { + padding: 0 24px; + overflow: visible; + color: #616161; + + p { + color: #616161; + } +} + +mat-dialog-content.mat-typography p { + color: #616161; +} diff --git a/src/app/shared/no-cira-warning/no-cira-warning.component.spec.ts b/src/app/shared/no-cira-warning/no-cira-warning.component.spec.ts new file mode 100644 index 000000000..8436c766b --- /dev/null +++ b/src/app/shared/no-cira-warning/no-cira-warning.component.spec.ts @@ -0,0 +1,39 @@ +/********************************************************************* + * Copyright (c) Intel Corporation 2022 + * SPDX-License-Identifier: Apache-2.0 + **********************************************************************/ + +import { ComponentFixture, TestBed } from '@angular/core/testing' +import { MatDialogModule } from '@angular/material/dialog' + +import { NoCIRAWarningComponent } from './no-cira-warning.component' +import { provideTranslateService } from '@ngx-translate/core' + +describe('NoCIRAWarningComponent', () => { + let component: NoCIRAWarningComponent + let fixture: ComponentFixture + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + MatDialogModule, + NoCIRAWarningComponent + ], + providers: [provideTranslateService()] + }) + }) + + beforeEach(() => { + fixture = TestBed.createComponent(NoCIRAWarningComponent) + component = fixture.componentInstance + fixture.detectChanges() + }) + + afterEach(() => { + TestBed.resetTestingModule() + }) + + it('should create', () => { + expect(component).toBeTruthy() + }) +}) diff --git a/src/app/shared/no-cira-warning/no-cira-warning.component.ts b/src/app/shared/no-cira-warning/no-cira-warning.component.ts new file mode 100644 index 000000000..9297760d0 --- /dev/null +++ b/src/app/shared/no-cira-warning/no-cira-warning.component.ts @@ -0,0 +1,28 @@ +/********************************************************************* + * Copyright (c) Intel Corporation 2022 + * SPDX-License-Identifier: Apache-2.0 + **********************************************************************/ + +import { Component } from '@angular/core' +import { MatButton } from '@angular/material/button' +import { CdkScrollable } from '@angular/cdk/scrolling' +import { MatDialogTitle, MatDialogContent, MatDialogActions, MatDialogClose } from '@angular/material/dialog' +import { TranslatePipe } from '@ngx-translate/core' +import { MatIcon } from '@angular/material/icon' + +@Component({ + selector: 'app-no-cira-warning', + templateUrl: './no-cira-warning.component.html', + styleUrls: ['./no-cira-warning.component.scss'], + imports: [ + MatDialogTitle, + CdkScrollable, + MatDialogContent, + MatDialogActions, + MatButton, + TranslatePipe, + MatDialogClose, + MatIcon + ] +}) +export class NoCIRAWarningComponent {} diff --git a/src/assets/i18n/ar.json b/src/assets/i18n/ar.json index b5ee316f8..7034ef01e 100644 --- a/src/assets/i18n/ar.json +++ b/src/assets/i18n/ar.json @@ -2176,6 +2176,22 @@ "description": "عنوان بطاقة الشبكات اللاسلكية", "value": "الشبكات اللاسلكية" }, + "noCira.confirm": { + "description": "سؤال تأكيد مربع الحوار لتحذير بدون CIRA", + "value": "هل تريد المتابعة؟" + }, + "noCira.hint": { + "description": "تلميح مربع الحوار لشرح كيفية إعادة تمكين CIRA على الخادم", + "value": "للحفاظ على تكوين CIRA، قم بتمكين CIRA على الخادم عن طريق تعيين APP_DISABLE_CIRA إلى false." + }, + "noCira.message": { + "description": "رسالة مربع الحوار تحذر من إزالة CIRA من الملف الشخصي", + "value": "يحتوي هذا الملف الشخصي على تكوين CIRA موجود، ولكن CIRA معطّل حاليًا على الخادم. سيؤدي حفظ هذا الملف الشخصي إلى إزالة تكوين CIRA." + }, + "noCira.title": { + "description": "عنوان مربع الحوار لتحذير إزالة CIRA", + "value": "سيتم إزالة تكوين CIRA" + }, "pba.label": { "description": "التسمية الخاصة بخانة الاختيار لتمكين أو تعطيل تطبيق الإقلاع الآمن أو تعطيله", "value": "فرض التمهيد الآمن" diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json index 9e671b31f..1bacd9dd9 100644 --- a/src/assets/i18n/de.json +++ b/src/assets/i18n/de.json @@ -2172,6 +2172,22 @@ "description": "Titel der Karte „Drahtlose Netzwerke”", "value": "Drahtlose Netzwerke" }, + "noCira.confirm": { + "description": "Bestätigungsfrage im Dialog für die CIRA-Warnung", + "value": "Möchten Sie fortfahren?" + }, + "noCira.hint": { + "description": "Hinweis im Dialog zur Wiederaktivierung von CIRA auf dem Server", + "value": "Um die CIRA-Konfiguration beizubehalten, aktivieren Sie CIRA auf dem Server, indem Sie APP_DISABLE_CIRA auf false setzen." + }, + "noCira.message": { + "description": "Dialogmeldung mit Warnung, dass CIRA aus dem Profil entfernt wird", + "value": "Dieses Profil verfügt über eine vorhandene CIRA-Konfiguration, aber CIRA ist derzeit auf dem Server deaktiviert. Das Speichern dieses Profils entfernt die CIRA-Konfiguration." + }, + "noCira.title": { + "description": "Dialog-Titel für CIRA-Entfernungswarnung", + "value": "CIRA-Konfiguration wird entfernt" + }, "pba.label": { "description": "Bezeichnung für das Kontrollkästchen zum Aktivieren oder Deaktivieren der sicheren Boot-Erzwingung", "value": "Secure Boot erzwingen" diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index ab3c01b2c..15b28dd7a 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -2777,6 +2777,22 @@ "description": "Warning message shown when adding a profile while WiFi is disabled", "value": "WiFi is currently disabled. This profile will not take effect until WiFi is enabled." }, + "noCira.confirm": { + "description": "Dialog confirmation question for no CIRA warning", + "value": "Do you want to continue?" + }, + "noCira.hint": { + "description": "Dialog hint explaining how to re-enable CIRA on the server", + "value": "To keep the CIRA configuration, enable CIRA on the server by setting APP_DISABLE_CIRA to false." + }, + "noCira.message": { + "description": "Dialog message warning that CIRA will be removed from the profile", + "value": "This profile has an existing CIRA configuration, but CIRA is currently disabled on the server. Saving this profile will remove the CIRA configuration." + }, + "noCira.title": { + "description": "Dialog title for CIRA removal warning", + "value": "CIRA configuration will be removed" + }, "pba.enforceCCMMessage": { "value": "Secure Boot is always enforced in Client Control Mode (CCM)" }, @@ -3093,6 +3109,14 @@ "description": "Label for wired 802.1x configuration field", "value": "Wired 802.1x Configuration" }, + "profiles.deleteProfile": { + "description": "Message for deleted profiles", + "value": "Profile deleted successfully" + }, + "profiles.ciraDisabledNoConfig": { + "description": "Tooltip shown when CIRA is disabled and the profile has no remote management connection configured", + "value": "CIRA is disabled on this server and this profile has no connection configuration. Devices provisioned with this profile will not be remotely manageable." + }, "profiles.ciraExportDisabled": { "description": "Shown when exporting a CIRA profile 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." diff --git a/src/assets/i18n/es.json b/src/assets/i18n/es.json index eca95d58a..5150a2e3a 100644 --- a/src/assets/i18n/es.json +++ b/src/assets/i18n/es.json @@ -2172,6 +2172,22 @@ "description": "Título de la tarjeta de redes inalámbricas", "value": "Redes inalámbricas" }, + "noCira.confirm": { + "description": "Pregunta de confirmación del cuadro de diálogo para la advertencia sin CIRA", + "value": "¿Desea continuar?" + }, + "noCira.hint": { + "description": "Sugerencia del cuadro de diálogo para explicar cómo volver a habilitar CIRA en el servidor", + "value": "Para mantener la configuración CIRA, habilite CIRA en el servidor estableciendo APP_DISABLE_CIRA en false." + }, + "noCira.message": { + "description": "Mensaje del cuadro de diálogo que advierte que CIRA se eliminará del perfil", + "value": "Este perfil tiene una configuración CIRA existente, pero CIRA está actualmente deshabilitado en el servidor. Guardar este perfil eliminará la configuración CIRA." + }, + "noCira.title": { + "description": "Título del cuadro de diálogo para la advertencia de eliminación de CIRA", + "value": "Se eliminará la configuración CIRA" + }, "pba.label": { "description": "Etiqueta para la casilla de verificación para activar o desactivar la aplicación de arranque seguro", "value": "Aplicar Secure Boot" diff --git a/src/assets/i18n/fi.json b/src/assets/i18n/fi.json index b6e8b1e5c..c18ddaea7 100644 --- a/src/assets/i18n/fi.json +++ b/src/assets/i18n/fi.json @@ -2172,6 +2172,22 @@ "description": "Langattomien verkkojen kortin otsikko", "value": "Langattomat verkot" }, + "noCira.confirm": { + "description": "Vahvistuskysymys valintaikkunassa CIRA-varoitukselle", + "value": "Haluatko jatkaa?" + }, + "noCira.hint": { + "description": "Valintaikkunan vihje CIRA:n uudelleenaktivoimiseksi palvelimella", + "value": "Säilytä CIRA-kokoonpano ottamalla CIRA käyttöön palvelimella asettamalla APP_DISABLE_CIRA arvoon false." + }, + "noCira.message": { + "description": "Valintaikkunan viesti, joka varoittaa CIRA:n poistamisesta profiilista", + "value": "Tällä profiililla on olemassa oleva CIRA-kokoonpano, mutta CIRA on tällä hetkellä poistettu käytöstä palvelimella. Tämän profiilin tallentaminen poistaa CIRA-kokoonpanon." + }, + "noCira.title": { + "description": "Valintaikkunan otsikko CIRA:n poistovaroitukselle", + "value": "CIRA-kokoonpano poistetaan" + }, "pba.label": { "description": "Merkintä valintaruudulle, jolla suojatun käynnistyksen valvonta otetaan käyttöön tai poistetaan käytöstä.", "value": "Secure Bootin käyttöönotto" diff --git a/src/assets/i18n/fr.json b/src/assets/i18n/fr.json index 7c248c9e9..768561631 100644 --- a/src/assets/i18n/fr.json +++ b/src/assets/i18n/fr.json @@ -2176,6 +2176,22 @@ "description": "Titre de la carte des réseaux sans fil", "value": "Réseaux sans fil" }, + "noCira.confirm": { + "description": "Question de confirmation de la boîte de dialogue pour l'avertissement sans CIRA", + "value": "Voulez-vous continuer ?" + }, + "noCira.hint": { + "description": "Indication de la boîte de dialogue pour expliquer comment réactiver CIRA sur le serveur", + "value": "Pour conserver la configuration CIRA, activez CIRA sur le serveur en définissant APP_DISABLE_CIRA sur false." + }, + "noCira.message": { + "description": "Message de la boîte de dialogue avertissant que la configuration CIRA sera supprimée du profil", + "value": "Ce profil dispose d'une configuration CIRA existante, mais CIRA est actuellement désactivé sur le serveur. L'enregistrement de ce profil supprimera la configuration CIRA." + }, + "noCira.title": { + "description": "Titre de la boîte de dialogue pour l'avertissement de suppression de CIRA", + "value": "La configuration CIRA sera supprimée" + }, "pba.label": { "description": "Étiquette de la case à cocher permettant d'activer ou de désactiver la mise en œuvre du démarrage sécurisé", "value": "Mise en œuvre de l'amorçage sécurisé" diff --git a/src/assets/i18n/he.json b/src/assets/i18n/he.json index f8f972955..8a21f371d 100644 --- a/src/assets/i18n/he.json +++ b/src/assets/i18n/he.json @@ -2168,6 +2168,22 @@ "description": "כותרת כרטיס הרשתות האלחוטיות", "value": "רשתות אלחוטיות" }, + "noCira.confirm": { + "description": "שאלת אישור בתיבת הדו-שיח לאזהרה ללא CIRA", + "value": "האם ברצונך להמשיך?" + }, + "noCira.hint": { + "description": "רמז בתיבת הדו-שיח להסבר כיצד להפעיל מחדש את CIRA בשרת", + "value": "כדי לשמור את תצורת ה-CIRA, הפעל את CIRA בשרת על ידי הגדרת APP_DISABLE_CIRA ל-false." + }, + "noCira.message": { + "description": "הודעת תיבת הדו-שיח המזהירה שתצורת CIRA תוסר מהפרופיל", + "value": "לפרופיל זה יש תצורת CIRA קיימת, אך CIRA כרגע מושבת בשרת. שמירת פרופיל זה תסיר את תצורת ה-CIRA." + }, + "noCira.title": { + "description": "כותרת תיבת הדו-שיח לאזהרת הסרת CIRA", + "value": "תצורת CIRA תוסר" + }, "pba.label": { "description": "תווית לתיבת הסימון כדי להפעיל או להשבית אכיפת אתחול מאובטחת", "value": "אוכף אתחול מאובטח" diff --git a/src/assets/i18n/it.json b/src/assets/i18n/it.json index a385a6dc0..518c88c18 100644 --- a/src/assets/i18n/it.json +++ b/src/assets/i18n/it.json @@ -2168,6 +2168,22 @@ "description": "Titolo della scheda delle reti wireless", "value": "Reti wireless" }, + "noCira.confirm": { + "description": "Domanda di conferma della finestra di dialogo per l'avviso senza CIRA", + "value": "Vuoi continuare?" + }, + "noCira.hint": { + "description": "Suggerimento della finestra di dialogo per spiegare come riabilitare CIRA sul server", + "value": "Per mantenere la configurazione CIRA, abilita CIRA sul server impostando APP_DISABLE_CIRA su false." + }, + "noCira.message": { + "description": "Messaggio della finestra di dialogo che avvisa che la configurazione CIRA verrà rimossa dal profilo", + "value": "Questo profilo ha una configurazione CIRA esistente, ma CIRA è attualmente disabilitato sul server. Il salvataggio di questo profilo rimuoverà la configurazione CIRA." + }, + "noCira.title": { + "description": "Titolo della finestra di dialogo per l'avviso di rimozione CIRA", + "value": "La configurazione CIRA verrà rimossa" + }, "pba.label": { "description": "Etichetta per la casella di controllo per abilitare o disabilitare l'applicazione del secure boot", "value": "Applicare l'avvio sicuro" diff --git a/src/assets/i18n/ja.json b/src/assets/i18n/ja.json index 52f10579b..a09789260 100644 --- a/src/assets/i18n/ja.json +++ b/src/assets/i18n/ja.json @@ -2168,6 +2168,22 @@ "description": "無線ネットワークカードの見出し", "value": "ワイヤレスネットワーク" }, + "noCira.confirm": { + "description": "CIRA警告ダイアログの確認質問", + "value": "続行しますか?" + }, + "noCira.hint": { + "description": "サーバーでCIRAを再有効化する方法を説明するダイアログのヒント", + "value": "CIRA設定を維持するには、APP_DISABLE_CIRAをfalseに設定してサーバーでCIRAを有効にしてください。" + }, + "noCira.message": { + "description": "CIRA設定がプロファイルから削除されることを警告するダイアログメッセージ", + "value": "このプロファイルには既存のCIRA設定がありますが、CIRAは現在サーバーで無効になっています。このプロファイルを保存すると、CIRA設定が削除されます。" + }, + "noCira.title": { + "description": "CIRA削除警告のダイアログタイトル", + "value": "CIRA設定が削除されます" + }, "pba.label": { "description": "セキュアブートの実施を有効または無効にするチェックボックスのラベル", "value": "セキュアブートの強制" diff --git a/src/assets/i18n/nl.json b/src/assets/i18n/nl.json index cc91c08f7..79f19ab51 100644 --- a/src/assets/i18n/nl.json +++ b/src/assets/i18n/nl.json @@ -2176,6 +2176,22 @@ "description": "Titel van de kaart voor draadloze netwerken", "value": "Draadloze netwerken" }, + "noCira.confirm": { + "description": "Bevestigingsvraag van het dialoogvenster voor de CIRA-waarschuwing", + "value": "Wilt u doorgaan?" + }, + "noCira.hint": { + "description": "Hint in het dialoogvenster over het opnieuw inschakelen van CIRA op de server", + "value": "Om de CIRA-configuratie te behouden, schakel CIRA in op de server door APP_DISABLE_CIRA in te stellen op false." + }, + "noCira.message": { + "description": "Bericht in het dialoogvenster dat waarschuwt dat de CIRA-configuratie uit het profiel wordt verwijderd", + "value": "Dit profiel heeft een bestaande CIRA-configuratie, maar CIRA is momenteel uitgeschakeld op de server. Het opslaan van dit profiel verwijdert de CIRA-configuratie." + }, + "noCira.title": { + "description": "Titel van het dialoogvenster voor de CIRA-verwijderingswarschuwing", + "value": "CIRA-configuratie wordt verwijderd" + }, "pba.label": { "description": "Label voor het selectievakje om veilige opstart te activeren of deactiveren", "value": "Secure Boot afdwingen" diff --git a/src/assets/i18n/ru.json b/src/assets/i18n/ru.json index 5bd3c6a10..8430a8b3d 100644 --- a/src/assets/i18n/ru.json +++ b/src/assets/i18n/ru.json @@ -2168,6 +2168,22 @@ "description": "Название карты беспроводных сетей", "value": "Беспроводные сети" }, + "noCira.confirm": { + "description": "Вопрос подтверждения в диалоге предупреждения без CIRA", + "value": "Хотите продолжить?" + }, + "noCira.hint": { + "description": "Подсказка в диалоге о повторном включении CIRA на сервере", + "value": "Чтобы сохранить конфигурацию CIRA, включите CIRA на сервере, установив APP_DISABLE_CIRA в значение false." + }, + "noCira.message": { + "description": "Сообщение диалога с предупреждением об удалении конфигурации CIRA из профиля", + "value": "Этот профиль имеет существующую конфигурацию CIRA, но CIRA в настоящее время отключён на сервере. Сохранение этого профиля удалит конфигурацию CIRA." + }, + "noCira.title": { + "description": "Заголовок диалога для предупреждения об удалении CIRA", + "value": "Конфигурация CIRA будет удалена" + }, "pba.label": { "description": "Метка для флажка, позволяющего включить или отключить применение безопасной загрузки", "value": "Обеспечение безопасной загрузки" diff --git a/src/assets/i18n/sv.json b/src/assets/i18n/sv.json index 3c4ae1052..3b25cc37d 100644 --- a/src/assets/i18n/sv.json +++ b/src/assets/i18n/sv.json @@ -2040,6 +2040,22 @@ "description": "Titel på kortet för trådlösa nätverk", "value": "Trådlösa nätverk" }, + "noCira.confirm": { + "description": "Bekräftelsefråga i dialogen för CIRA-varningen", + "value": "Vill du fortsätta?" + }, + "noCira.hint": { + "description": "Tips i dialogen om hur man återaktiverar CIRA på servern", + "value": "För att behålla CIRA-konfigurationen, aktivera CIRA på servern genom att ange APP_DISABLE_CIRA till false." + }, + "noCira.message": { + "description": "Dialogmeddelande som varnar för att CIRA-konfigurationen tas bort från profilen", + "value": "Den här profilen har en befintlig CIRA-konfiguration, men CIRA är för närvarande inaktiverat på servern. Om du sparar den här profilen tas CIRA-konfigurationen bort." + }, + "noCira.title": { + "description": "Dialogtitel för CIRA-borttagningsvarningen", + "value": "CIRA-konfigurationen kommer att tas bort" + }, "pba.label": { "description": "Etikett för kryssrutan för att aktivera eller inaktivera säker start", "value": "Genomdriva säker start"