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
2 changes: 1 addition & 1 deletion src/app/devices/kvm/kvm.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
<button mat-flat-button color="primary" style="margin-right: 16px" (click)="toggleFullscreen()">
<mat-icon>fullscreen</mat-icon>{{ 'kvm.fullscreen.button.value' | translate }}
</button>
@if (deviceState() === 0 && !isLoading()) {
@if ((deviceState() === 0 || !deviceKVMConnection()) && !isLoading()) {
<button mat-flat-button color="primary" style="margin-right: 16px" (click)="connect()">
<mat-icon>tv_on</mat-icon>{{ 'kvm.connect.button.value' | translate }}
</button>
Expand Down
47 changes: 44 additions & 3 deletions src/app/devices/kvm/kvm.component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ describe('KvmComponent', () => {
let snackBarSpy: jasmine.Spy
let router: Router
let displayErrorSpy: jasmine.Spy
let displayWarningSpy: jasmine.Spy
let devicesService: jasmine.SpyObj<DevicesService>
let userConsentService: jasmine.SpyObj<UserConsentService>

Expand Down Expand Up @@ -201,6 +202,7 @@ describe('KvmComponent', () => {
spyOn(router, 'navigate')

displayErrorSpy = spyOn(component, 'displayError').and.callThrough()
displayWarningSpy = spyOn(component, 'displayWarning').and.callThrough()
})

afterEach(() => {
Expand All @@ -220,16 +222,40 @@ describe('KvmComponent', () => {
// Initial state should be disconnected since we changed to signal(false)
expect(component.deviceKVMConnection()).toBeFalsy()

// Test connect method
// Test connect method — resets state, refreshes token, then re-establishes via init()
component.readyToLoadKvm = true
component.connect()
expect(component.isDisconnecting).toBeFalsy()
expect(tokenSpy).toHaveBeenCalled()
// After synchronous observables complete in test env, connection is re-established
expect(component.deviceKVMConnection()).toBeTruthy()

// Test disconnect method
component.disconnect()
expect(component.isDisconnecting).toBeTruthy()
expect(component.deviceKVMConnection()).toBeFalsy()
})
it('connect() resets readyToLoadKvm and deviceKVMConnection to false before reconnecting', () => {
component.readyToLoadKvm = true
component.deviceKVMConnection.set(true)
// Intercept init to observe intermediate reset state
let readyToLoadKvmAtStartOfInit = true
let connectionAtStartOfInit = true
spyOn(component, 'init').and.callFake(() => {
readyToLoadKvmAtStartOfInit = component.readyToLoadKvm
connectionAtStartOfInit = component.deviceKVMConnection()
})
component.connect()
expect(readyToLoadKvmAtStartOfInit).toBeFalse()
expect(connectionAtStartOfInit).toBeFalse()
})
it('connect() refreshes auth token via getRedirectionExpirationToken before calling init', () => {
tokenSpy.calls.reset()
spyOn(component, 'init')
component.connect()
expect(tokenSpy).toHaveBeenCalledTimes(1)
expect(component.authToken()).toBe('123')
})
it('should not show error and hide loading when isDisconnecting is true', () => {
component.isDisconnecting = true
component.deviceKVMStatus(0)
Expand All @@ -239,10 +265,25 @@ describe('KvmComponent', () => {
})
it('should show error and hide loading when isDisconnecting is false', () => {
component.isDisconnecting = false
component.deviceKVMConnection.set(true)
component.deviceKVMStatus(0)
expect(snackBarSpy).toHaveBeenCalledOnceWith('error.kvmConnection.value', undefined, SnackbarDefaults.defaultError)
expect(snackBarSpy).toHaveBeenCalledOnceWith(
'kvm.sessionClosedByDevice.value',
undefined,
SnackbarDefaults.defaultWarn
)
expect(component.isLoading()).toBeFalse()
expect(component.deviceState()).toBe(0)
// AMT dropped the connection — deviceKVMConnection must be reset so Connect button appears
expect(component.deviceKVMConnection()).toBeFalse()
})
it('should not reset deviceKVMConnection when isDisconnecting is true (intentional disconnect)', () => {
component.isDisconnecting = true
component.deviceKVMConnection.set(true)
component.deviceKVMStatus(0)
expect(snackBarSpy).not.toHaveBeenCalled()
// intentional disconnect — caller manages connection state via disconnect()
expect(component.deviceKVMConnection()).toBeTrue()
})
it('should hide loading when connected', () => {
component.deviceKVMStatus(2)
Expand Down Expand Up @@ -650,7 +691,7 @@ describe('KvmComponent', () => {
component.isDisconnecting = false
component.deviceKVMStatus(0)
expect(component.isLoading()).toEqual(false)
expect(displayErrorSpy).toHaveBeenCalled()
expect(displayWarningSpy).toHaveBeenCalled()
expect(component.isDisconnecting).toEqual(false)
})
it('displayError', () => {
Expand Down
19 changes: 15 additions & 4 deletions src/app/devices/kvm/kvm.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,9 +312,18 @@ export class KvmComponent implements OnInit, OnDestroy {

connect(): void {
this.isDisconnecting = false
this.deviceState.set(-1) // Reset device state for reconnection
this.init()
this.deviceKVMConnection.set(true)
this.deviceState.set(-1)
this.readyToLoadKvm = false
this.deviceKVMConnection.set(false)
// Refresh the auth token before reconnecting in case it has expired
this.devicesService
.getRedirectionExpirationToken(this.deviceId())
.pipe(
tap((result) => {
this.authToken.set(result.token)
})
)
.subscribe({ next: () => this.init() })
}
@HostListener('window:beforeunload')
beforeUnloadHandler() {
Expand Down Expand Up @@ -509,7 +518,9 @@ export class KvmComponent implements OnInit, OnDestroy {
this.isLoading.set(false)
this.loadingStatus.set('')
if (!this.isDisconnecting && !this.isEncodingChange) {
this.displayError(this.translate.instant('error.kvmConnection.value'))
// AMT dropped the connection - reset so button shows "Connect KVM"
this.deviceKVMConnection.set(false)
this.displayWarning(this.translate.instant('kvm.sessionClosedByDevice.value'))
}
this.isDisconnecting = false
}
Expand Down
14 changes: 3 additions & 11 deletions src/app/error-handling.interceptor.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,20 +82,12 @@ describe('ErrorHandlingInterceptor', () => {
})

it('should handle 504 error and show snackbar', () => {
httpClient.get('/test').subscribe({
error: () => {
expect(snackbar.open).toHaveBeenCalledWith(
'Device did not respond. Double check connection settings and try again.',
'Dismiss',
{
duration: 5000
}
)
}
})
httpClient.get('/test').subscribe()

const req = httpMock.expectOne('/test')
req.flush({}, { status: 504, statusText: 'Gateway Timeout' })

expect(snackbar.open).toHaveBeenCalledOnceWith(jasmine.any(String), jasmine.any(String), { duration: 5000 })
})

it('should rethrow other errors', () => {
Expand Down
4 changes: 4 additions & 0 deletions src/assets/i18n/ar.json
Original file line number Diff line number Diff line change
Expand Up @@ -1652,6 +1652,10 @@
"description": "التسمية التي تظهر عند اتصال KVM",
"value": "توصيل KVM..."
},
"kvm.sessionClosedByDevice": {
"description": "رسالة تظهر عند إغلاق AMT لجلسة KVM",
"value": "تم إغلاق جلسة KVM بواسطة AMT"
},
"kvm.disconnect.button": {
"description": "تسمية الزر لقطع الاتصال بجلسة KVM",
"value": "فصل KVM"
Expand Down
4 changes: 4 additions & 0 deletions src/assets/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -1652,6 +1652,10 @@
"description": "Bezeichnung, die angezeigt wird, wenn KVM eine Verbindung herstellt",
"value": "KVM wird verbunden..."
},
"kvm.sessionClosedByDevice": {
"description": "Meldung, wenn AMT die KVM-Sitzung schließt",
"value": "KVM-Sitzung wurde von AMT geschlossen"
},
"kvm.disconnect.button": {
"description": "Schaltflächenbeschriftung zum Trennen der Verbindung zur KVM-Sitzung",
"value": "KVM trennen"
Expand Down
4 changes: 4 additions & 0 deletions src/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1839,6 +1839,10 @@
"description": "Button label to disconnect from KVM session",
"value": "Disconnect KVM"
},
"kvm.sessionClosedByDevice": {
"description": "Message shown when AMT closes the KVM session (e.g. idle timeout)",
"value": "KVM session was closed by AMT"
},
"kvm.enable": {
"description": "Message for enabling KVM",
"value": "KVM is not currently enabled on this device. Would you like to enable it?"
Expand Down
4 changes: 4 additions & 0 deletions src/assets/i18n/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -1652,6 +1652,10 @@
"description": "Etiqueta que se muestra cuando KVM se está conectando.",
"value": "Conectando KVM..."
},
"kvm.sessionClosedByDevice": {
"description": "Mensaje que se muestra cuando AMT cierra la sesión KVM",
"value": "La sesión KVM fue cerrada por AMT"
},
"kvm.disconnect.button": {
"description": "Etiqueta del botón para desconectarse de la sesión KVM.",
"value": "Desconectar KVM"
Expand Down
4 changes: 4 additions & 0 deletions src/assets/i18n/fi.json
Original file line number Diff line number Diff line change
Expand Up @@ -1652,6 +1652,10 @@
"description": "KVM-yhteyden muodostamisen aikana näkyvä etiketti",
"value": "KVM:n yhdistäminen..."
},
"kvm.sessionClosedByDevice": {
"description": "Viesti, joka näytetään kun AMT sulkee KVM-istunnon",
"value": "AMT sulki KVM-istunnon"
},
"kvm.disconnect.button": {
"description": "Painikkeen teksti KVM-istunnon katkaisemiseksi",
"value": "Kytke KVM irti"
Expand Down
4 changes: 4 additions & 0 deletions src/assets/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -1652,6 +1652,10 @@
"description": "Étiquette affichée lorsque KVM se connecte",
"value": "Connexion KVM..."
},
"kvm.sessionClosedByDevice": {
"description": "Message affiché quand AMT ferme la session KVM",
"value": "La session KVM a été fermée par AMT"
},
"kvm.disconnect.button": {
"description": "Étiquette du bouton pour se déconnecter de la session KVM",
"value": "Déconnecter KVM"
Expand Down
4 changes: 4 additions & 0 deletions src/assets/i18n/he.json
Original file line number Diff line number Diff line change
Expand Up @@ -1652,6 +1652,10 @@
"description": "תווית מוצגת כאשר KVM מתחבר",
"value": "חיבור KVM ..."
},
"kvm.sessionClosedByDevice": {
"description": "הודעה המוצגת כאשר AMT סוגר את הפגישה של KVM",
"value": "הפגישה של KVM נסגרה על ידי AMT"
},
"kvm.disconnect.button": {
"description": "תווית כפתור לניתוק מפגישת KVM",
"value": "נתק את KVM"
Expand Down
4 changes: 4 additions & 0 deletions src/assets/i18n/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -1652,6 +1652,10 @@
"description": "Etichetta visualizzata quando KVM è in fase di connessione",
"value": "Connessione KVM in corso..."
},
"kvm.sessionClosedByDevice": {
"description": "Messaggio mostrato quando AMT chiude la sessione KVM",
"value": "La sessione KVM è stata chiusa da AMT"
},
"kvm.disconnect.button": {
"description": "Etichetta del pulsante per disconnettersi dalla sessione KVM",
"value": "Disconnetti KVM"
Expand Down
4 changes: 4 additions & 0 deletions src/assets/i18n/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -1652,6 +1652,10 @@
"description": "KVMが接続中の際に表示されるラベル",
"value": "KVMを接続中..."
},
"kvm.sessionClosedByDevice": {
"description": "AMTがKVMセッションを閉じたときに表示されるメッセージ",
"value": "KVMセッションはAMTによって閉じられました"
},
"kvm.disconnect.button": {
"description": "KVMセッションから切断するボタンラベル",
"value": "KVMの切断"
Expand Down
4 changes: 4 additions & 0 deletions src/assets/i18n/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -1652,6 +1652,10 @@
"description": "Label dat wordt weergegeven wanneer KVM verbinding maakt",
"value": "KVM verbinden..."
},
"kvm.sessionClosedByDevice": {
"description": "Bericht getoond wanneer AMT de KVM-sessie sluit",
"value": "KVM-sessie is gesloten door AMT"
},
"kvm.disconnect.button": {
"description": "Knoplabel om de verbinding met de KVM-sessie te verbreken",
"value": "KVM loskoppelen"
Expand Down
4 changes: 4 additions & 0 deletions src/assets/i18n/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -1652,6 +1652,10 @@
"description": "Метка, отображаемая при подключении KVM",
"value": "Подключение KVM..."
},
"kvm.sessionClosedByDevice": {
"description": "Сообщение, отображаемое когда AMT закрывает сеанс KVM",
"value": "Сеанс KVM был закрыт AMT"
},
"kvm.disconnect.button": {
"description": "Метка кнопки для отключения от сеанса KVM",
"value": "Отключить KVM"
Expand Down
4 changes: 4 additions & 0 deletions src/assets/i18n/sv.json
Original file line number Diff line number Diff line change
Expand Up @@ -1652,6 +1652,10 @@
"description": "Etikett som visas när KVM ansluter",
"value": "Ansluter KVM..."
},
"kvm.sessionClosedByDevice": {
"description": "Meddelande som visas när AMT stänger KVM-sessionen",
"value": "KVM-sessionen stängdes av AMT"
},
"kvm.disconnect.button": {
"description": "Knappetikett för att koppla bort från KVM-sessionen",
"value": "Koppla bort KVM"
Expand Down
Loading