diff --git a/webapp/src/client/app/app.module.ts b/webapp/src/client/app/app.module.ts
index ea96a76b0..33e8568a1 100644
--- a/webapp/src/client/app/app.module.ts
+++ b/webapp/src/client/app/app.module.ts
@@ -32,6 +32,7 @@ import { SidebarModule } from "primeng/sidebar";
import { ToastModule } from "primeng/toast";
import { TabView, TabViewModule } from "primeng/tabview";
import { AutoCompleteModule } from "primeng/autocomplete";
+import { SshKeyService } from './shared/services/ssh-key.service';
@NgModule({
@@ -67,6 +68,7 @@ import { AutoCompleteModule } from "primeng/autocomplete";
LoadingService,
WebSessionService,
WebClientService,
+ SshKeyService,
TabView
],
exports: [
diff --git a/webapp/src/client/app/modules/web-client/form/form-components/ssh/ssh-form.component.html b/webapp/src/client/app/modules/web-client/form/form-components/ssh/ssh-form.component.html
index 5e2ca5b42..3e780da77 100644
--- a/webapp/src/client/app/modules/web-client/form/form-components/ssh/ssh-form.component.html
+++ b/webapp/src/client/app/modules/web-client/form/form-components/ssh/ssh-form.component.html
@@ -1,11 +1,23 @@
\ No newline at end of file
diff --git a/webapp/src/client/app/modules/web-client/form/form-components/ssh/ssh-form.component.ts b/webapp/src/client/app/modules/web-client/form/form-components/ssh/ssh-form.component.ts
index 8a484524c..20823049f 100644
--- a/webapp/src/client/app/modules/web-client/form/form-components/ssh/ssh-form.component.ts
+++ b/webapp/src/client/app/modules/web-client/form/form-components/ssh/ssh-form.component.ts
@@ -1,23 +1,126 @@
-import {Component, Input, OnInit} from '@angular/core';
-import {FormGroup} from "@angular/forms";
+import {
+ AfterViewInit,
+ Component,
+ Injectable,
+ Input,
+ OnDestroy,
+ OnInit,
+} from '@angular/core';
+import { FormControl, FormGroup } from '@angular/forms';
-import {BaseComponent} from "@shared/bases/base.component";
+import { BaseComponent } from '@shared/bases/base.component';
+import { SelectItem } from 'primeng/api';
+import { WebFormService } from '@gateway/shared/services/web-form.service';
+import { map, startWith, switchMap, takeUntil, tap } from 'rxjs/operators';
+import { SshAuthMode } from '@gateway/shared/enums/web-client-auth-mode.enum';
+import { Observable, of } from 'rxjs';
+import { SshKeyService } from '@gateway/shared/services/ssh-key.service';
+interface FormInputVisibility {
+ showUsernameInput?: boolean;
+ showPasswordInput?: boolean;
+ showPrivateKeyInput?: boolean;
+}
+
+@Injectable({ providedIn: 'root' })
@Component({
selector: 'ssh-form',
templateUrl: 'ssh-form.component.html',
- styleUrls: ['ssh-form.component.scss']
+ styleUrls: ['ssh-form.component.scss'],
})
-export class SshFormComponent extends BaseComponent implements OnInit {
-
+export class SshFormComponent
+ extends BaseComponent
+ implements OnInit, OnDestroy, AfterViewInit
+{
@Input() form: FormGroup;
@Input() inputFormData: any;
- constructor() {
+ authModeOptions: SelectItem[];
+
+ formInputVisibility: FormInputVisibility = {
+ showUsernameInput: true,
+ showPasswordInput: true,
+ showPrivateKeyInput: false,
+ };
+
+ constructor(
+ private formService: WebFormService,
+ private sshKeyService: SshKeyService
+ ) {
super();
}
+ ngAfterViewInit(): void {
+ this.formService.canConnectIfAlsoTrue(() => {
+ if (!this.formInputVisibility.showPrivateKeyInput) {
+ return true;
+ }
+
+ return this.sshKeyService.hasValidPrivateKey();
+ });
+ }
+
ngOnInit(): void {
+ this.initializeFormOptions();
+ this.addControlsToParentForm(this.inputFormData);
+ }
+
+ ngOnDestroy(): void {
+ this.formService.resetCanConnectCallback();
+ }
+
+ private addControlsToParentForm(inputFormData?: any): void {
+ if (this.form) {
+ this.form.addControl(
+ 'authMode',
+ new FormControl(
+ inputFormData?.authMode || SshAuthMode.Username_and_Password
+ )
+ );
+ this.subscribeToAuthModeChanges();
+ }
+ }
+
+ private initializeFormOptions(): void {
+ this.formService
+ .getAuthModeOptions('ssh')
+ .pipe(takeUntil(this.destroyed$))
+ .subscribe({
+ next: (authModeOptions) => {
+ this.authModeOptions = authModeOptions;
+ },
+ error: (error) =>
+ console.error('Error fetching dropdown options', error),
+ });
+ }
+
+ private subscribeToAuthModeChanges(): void {
+ this.form
+ .get('authMode')
+ .valueChanges.pipe(
+ takeUntil(this.destroyed$),
+ startWith(this.form.get('authMode').value as SshAuthMode),
+ switchMap((authMode) => this.getFormInputVisibility(authMode))
+ )
+ .subscribe(() => {});
+ }
+
+ private getFormInputVisibility(
+ authMode: SshAuthMode
+ ): Observable {
+ return of(this.formInputVisibility).pipe(
+ tap((visibility) => {
+ visibility.showUsernameInput =
+ authMode === SshAuthMode.Username_and_Password ||
+ authMode === SshAuthMode.Private_Key;
+ visibility.showPasswordInput =
+ authMode === SshAuthMode.Username_and_Password;
+ visibility.showPrivateKeyInput = authMode === SshAuthMode.Private_Key;
+ }),
+ map(() => {
+ return authMode;
+ })
+ );
}
}
diff --git a/webapp/src/client/app/modules/web-client/form/form-components/vnc/vnc-form.component.ts b/webapp/src/client/app/modules/web-client/form/form-components/vnc/vnc-form.component.ts
index 1a469e302..acbae629a 100644
--- a/webapp/src/client/app/modules/web-client/form/form-components/vnc/vnc-form.component.ts
+++ b/webapp/src/client/app/modules/web-client/form/form-components/vnc/vnc-form.component.ts
@@ -5,8 +5,8 @@ import {BaseComponent} from "@shared/bases/base.component";
import {SelectItem} from "primeng/api";
import {map, startWith, switchMap, takeUntil, tap} from "rxjs/operators";
import {WebFormService} from "@shared/services/web-form.service";
-import {AuthMode} from "@shared/enums/web-client-auth-mode.enum";
import {Observable, of} from "rxjs";
+import { VncAuthMode as AuthMode } from '@shared/enums/web-client-auth-mode.enum';
interface FormInputVisibility {
showUsernameInput?: boolean;
@@ -56,7 +56,7 @@ export class VncFormComponent extends BaseComponent implements OnInit {
}
private initializeFormOptions(): void {
- this.formService.getAuthModeOptions().pipe(
+ this.formService.getAuthModeOptions('vnc').pipe(
takeUntil(this.destroyed$)
).subscribe({
next: (authModeOptions) => {
diff --git a/webapp/src/client/app/modules/web-client/form/form-controls/file-control/file-control.component.html b/webapp/src/client/app/modules/web-client/form/form-controls/file-control/file-control.component.html
new file mode 100644
index 000000000..0e4251455
--- /dev/null
+++ b/webapp/src/client/app/modules/web-client/form/form-controls/file-control/file-control.component.html
@@ -0,0 +1,47 @@
+
+
diff --git a/webapp/src/client/app/modules/web-client/form/form-controls/file-control/file-control.component.scss b/webapp/src/client/app/modules/web-client/form/form-controls/file-control/file-control.component.scss
new file mode 100644
index 000000000..3dd10dc15
--- /dev/null
+++ b/webapp/src/client/app/modules/web-client/form/form-controls/file-control/file-control.component.scss
@@ -0,0 +1,91 @@
+@import '../../../../../../../assets/css/style/mixins';
+@import "../../../../../../../assets/css/style/variables";
+@import "../../../../../../../assets/css/theme/theme-mode-variables";
+
+::ng-deep p-fileUpload .p-fileupload-content .p-progressbar {
+ display: none !important;
+}
+
+.file-container {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin: 10px 5px 10px 5px;
+}
+
+.form-helper-text {
+ line-height: 11px;
+ word-wrap: break-word;
+ color: var(--status-error-text-color);
+ font-size: 11px;
+ font-family: Open Sans;
+ font-weight: 400;
+ padding-left: 0px;
+ justify-content: flex-start;
+ align-items: flex-start;
+ gap: 10px;
+ display: inline-flex
+}
+
+.highlight {
+ background-color: #f0f0f0;
+}
+
+.gateway-form-group {
+ padding: 0px 0px 18px 0px;
+}
+
+.flex-row{
+ display: flex;
+ align-items: center;
+}
+
+.justify-end {
+ justify-content: end;
+}
+
+.private-key-textarea{
+ margin-top: 5px;
+ margin-bottom: 5px;
+ resize: none;
+ font-family: monospace;
+ font-size: xx-small;
+ line-height: 15px;
+}
+
+.card {
+ border-radius: 10px;
+ margin-bottom: 1rem;
+}
+
+.card p-fileupload {
+ width: 100%;
+}
+
+::ng-deep .card p-fileupload .p-fileupload-buttonbar {
+ display: flex;
+ justify-content: end;
+ flex-direction: row !important;
+}
+
+::ng-deep .card p-fileupload div {
+ display: flex;
+ flex-direction: column-reverse;
+}
+
+.file-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+}
+
+::ng-deep .card p-fileupload .p-button {
+ background-color: white;
+ border : 1px solid var(--default-btn-bg-color);
+ color: var(--default-btn-bg-color);
+}
+
+::ng-deep .card p-fileupload .p-button:hover {
+ background-color: var(--default-btn-bg-color);
+ color: white;
+}
\ No newline at end of file
diff --git a/webapp/src/client/app/modules/web-client/form/form-controls/file-control/file-control.component.ts b/webapp/src/client/app/modules/web-client/form/form-controls/file-control/file-control.component.ts
new file mode 100644
index 000000000..674817a7c
--- /dev/null
+++ b/webapp/src/client/app/modules/web-client/form/form-controls/file-control/file-control.component.ts
@@ -0,0 +1,102 @@
+import {
+ Component,
+ ElementRef,
+ Input,
+ OnDestroy,
+ OnInit,
+ ViewChild,
+} from '@angular/core';
+import { SshKeyService } from '@gateway/shared/services/ssh-key.service';
+import { ValidateFileResult } from '../../../../../shared/services/ssh-key.service';
+import { WebFormService } from '@gateway/shared/services/web-form.service';
+
+@Component({
+ selector: 'app-file-control',
+ templateUrl: './file-control.component.html',
+ styleUrls: ['./file-control.component.scss'],
+})
+export class FileControlComponent implements OnInit, OnDestroy {
+ @ViewChild('publicKeyFileControl') publicKeyFileControl: ElementRef;
+
+ private uploadedFile: File = null;
+ private fileValidateResult: ValidateFileResult = null;
+ privateKeyContent: string = '';
+
+ constructor(
+ private sshKeyService: SshKeyService,
+ private formService: WebFormService
+ ) {
+ this.uploadedFile = sshKeyService.getKeyFile();
+ this.privateKeyContent = sshKeyService.getKeyContent();
+ }
+
+ ngOnDestroy(): void {
+ this.formService.resetCanConnectCallback();
+ }
+
+ ngOnInit(): void {
+ this.formService.canConnectIfAlsoTrue(() => {
+ return this.sshKeyService.hasValidPrivateKey();
+ });
+ }
+
+ clearPublicKeyData() {
+ this.privateKeyContent = '';
+ this.sshKeyService.removeFile();
+ this.uploadedFile = null;
+ }
+ onDragEnter(event: any) {
+ event.preventDefault();
+ event.stopPropagation();
+ }
+
+ onSelect(event) {
+ this.handleFiles(event.files);
+ }
+
+ handleFiles(fileList: FileList) {
+ if (fileList.length !== 1) {
+ return;
+ }
+
+ this.uploadedFile = fileList[0];
+
+ this.sshKeyService.validateFile(this.uploadedFile).subscribe((res) => {
+ this.fileValidateResult = res;
+ this.privateKeyContent = this.fileValidateResult.content || '';
+ if (this.fileValidateResult.valid) {
+ this.sshKeyService.saveFile(
+ this.uploadedFile,
+ this.fileValidateResult.content
+ );
+ }
+ });
+ }
+
+ isValidFile(): boolean {
+ return this.fileValidateResult ? this.fileValidateResult.valid : false;
+ }
+
+ removeFile() {
+ this.uploadedFile = null;
+ this.fileValidateResult = null;
+ this.sshKeyService.removeFile();
+ }
+
+ getErrorMessage(): String {
+ if (!this.fileValidateResult) {
+ return '';
+ }
+ if (this.fileValidateResult.valid === false) {
+ return this.fileValidateResult.error;
+ }
+ return '';
+ }
+
+ getFileSize(): string {
+ if (!this.uploadedFile) {
+ return '';
+ }
+ return `${this.uploadedFile.size} bytes`;
+ }
+}
diff --git a/webapp/src/client/app/modules/web-client/form/web-client-form.component.html b/webapp/src/client/app/modules/web-client/form/web-client-form.component.html
index fd8e92f50..df7d6fe2e 100644
--- a/webapp/src/client/app/modules/web-client/form/web-client-form.component.html
+++ b/webapp/src/client/app/modules/web-client/form/web-client-form.component.html
@@ -74,7 +74,7 @@