From 1ac659fd909942b4170ee62adc122fcb90ea4ac5 Mon Sep 17 00:00:00 2001 From: Khanjan Dalwadi <17khanjan@gmail.com> Date: Thu, 20 Jun 2024 16:25:12 +0530 Subject: [PATCH 1/3] Import Feature flag modal implemented --- .../import-feature-flag-modal.component.html | 39 ++++++++ .../import-feature-flag-modal.component.scss | 51 ++++++++++ .../import-feature-flag-modal.component.ts | 93 +++++++++++++++++++ .../shared/services/common-dialog.service.ts | 18 ++++ 4 files changed, 201 insertions(+) create mode 100644 frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.html create mode 100644 frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.scss create mode 100644 frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.ts diff --git a/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.html b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.html new file mode 100644 index 0000000000..d75db3581d --- /dev/null +++ b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.html @@ -0,0 +1,39 @@ + diff --git a/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.scss b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.scss new file mode 100644 index 0000000000..2a7dbce664 --- /dev/null +++ b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.scss @@ -0,0 +1,51 @@ +.drag-drop-container { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + width: 100%; + height: 100%; + color: grey; + + mat-icon { + height: 70px; + width: 70px; + font-size: 70px; + color: grey; + } +} + +.input-container { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + border: 1px dashed grey; + border-radius: 4px; + height: 206px; + width: 592px; + position: relative; + + button { + font-size: 14px; + } +} +.input-container-header { + position: absolute; + top: 5px; + right: 5px; + + mat-icon { + height: 24px; + width: 24px; + font-size: 24px; + } +} +p { + color: grey; + font-size: 12px; +} + +a { + text-decoration: none; +} diff --git a/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.ts b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.ts new file mode 100644 index 0000000000..0d2d2395cb --- /dev/null +++ b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.ts @@ -0,0 +1,93 @@ +import { ChangeDetectionStrategy, Component, ElementRef, Inject, OnInit, ViewChild } from '@angular/core'; +import { CommonModalComponent } from '../../../../../shared-standalone-component-lib/components'; +import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; +import { CommonModalConfig } from '../../../../../shared-standalone-component-lib/components/common-modal/common-modal-config'; +import { FeatureFlagsService } from '../../../../../core/feature-flags/feature-flags.service'; +import { BehaviorSubject, Observable, Subscription, combineLatest, map } from 'rxjs'; +import { CommonModule } from '@angular/common'; +import { SharedModule } from '../../../../../shared/shared.module'; + +@Component({ + selector: 'app-import-feature-flag-modal', + standalone: true, + imports: [CommonModalComponent, CommonModule, SharedModule], + templateUrl: './import-feature-flag-modal.component.html', + styleUrl: './import-feature-flag-modal.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ImportFeatureFlagModalComponent { + @ViewChild('fileInput') fileInput: ElementRef; + + isImportActionBtnDisabled = new BehaviorSubject(true); + isDragOver = false; + fileName: string | null = null; + + constructor( + @Inject(MAT_DIALOG_DATA) + public data: CommonModalConfig & { flagName: string; flagId: string }, + public dialog: MatDialog, + private featureFlagsService: FeatureFlagsService, + public dialogRef: MatDialogRef + ) {} + + onDragOver(event: DragEvent): void { + event.preventDefault(); + event.stopPropagation(); + this.isDragOver = true; + } + + onDragLeave(event: DragEvent): void { + event.preventDefault(); + event.stopPropagation(); + this.isDragOver = false; + } + + onDrop(event: DragEvent): void { + event.preventDefault(); + event.stopPropagation(); + this.isDragOver = false; + + const files = event.dataTransfer?.files; + if (files && files.length > 0) { + const file = files[0]; + if (file.type === 'application/json') { + this.fileName = file.name; + this.isImportActionBtnDisabled.next(false); + this.handleFileInput(file); + } else { + alert('Please upload a valid JSON file.'); + this.fileName = null; + this.isImportActionBtnDisabled.next(true); + } + } + } + + onFileSelected(event: Event): void { + const input = event.target as HTMLInputElement; + if (input.files && input.files.length > 0) { + const file = input.files[0]; + if (file.type === 'application/json') { + this.fileName = file.name; + this.isImportActionBtnDisabled.next(false); + this.handleFileInput(file); + } else { + alert('Please upload a valid JSON file.'); + this.fileName = null; + this.isImportActionBtnDisabled.next(true); + } + } + } + + handleFileInput(file: File): void { + const reader = new FileReader(); + reader.onload = (e: any) => { + const jsonContent = e.target.result; + console.log(JSON.parse(jsonContent)); + }; + reader.readAsText(file); + } + + closeModal() { + this.dialogRef.close(); + } +} diff --git a/frontend/projects/upgrade/src/app/shared/services/common-dialog.service.ts b/frontend/projects/upgrade/src/app/shared/services/common-dialog.service.ts index b512bdb2fe..e0e43c0c15 100644 --- a/frontend/projects/upgrade/src/app/shared/services/common-dialog.service.ts +++ b/frontend/projects/upgrade/src/app/shared/services/common-dialog.service.ts @@ -5,6 +5,7 @@ import { AddFeatureFlagModalComponent } from '../../features/dashboard/feature-f import { CommonModalConfig } from '../../shared-standalone-component-lib/components/common-modal/common-modal-config'; import { DeleteFeatureFlagModalComponent } from '../../features/dashboard/feature-flags/modals/delete-feature-flag-modal/delete-feature-flag-modal.component'; import { EnableFeatureFlagModalComponent } from '../../features/dashboard/feature-flags/modals/enable-feature-flag-modal/enable-feature-flag-modal.component'; +import { ImportFeatureFlagModalComponent } from '../../features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component'; @Injectable({ providedIn: 'root', @@ -68,4 +69,21 @@ export class DialogService { }; return this.dialog.open(DeleteFeatureFlagModalComponent, config); } + + openImportFeatureFlagModal() { + const commonModalConfig: CommonModalConfig = { + title: 'Import Feature Flag', + primaryActionBtnLabel: 'Import', + primaryActionBtnColor: 'primary', + cancelBtnLabel: 'Cancel', + }; + const config: MatDialogConfig = { + data: commonModalConfig, + width: '670px', + height: '450px', + autoFocus: 'input', + disableClose: true, + }; + return this.dialog.open(ImportFeatureFlagModalComponent, config); + } } From 1e3b437e3d087659fe281a7c4860e86045a4d280 Mon Sep 17 00:00:00 2001 From: Khanjan Dalwadi <17khanjan@gmail.com> Date: Fri, 21 Jun 2024 11:22:19 +0530 Subject: [PATCH 2/3] Enabled menu button and linked up the modal with it --- .../import-feature-flag-modal.component.html | 2 +- .../import-feature-flag-modal.component.scss | 9 +++++++++ .../feature-flag-root-section-card.component.html | 1 + .../feature-flag-root-section-card.component.ts | 6 +++++- 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.html b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.html index d75db3581d..6e313786a3 100644 --- a/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.html +++ b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.html @@ -17,7 +17,7 @@
close
-
+
insert_drive_file

{{ fileName }}

diff --git a/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.scss b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.scss index 2a7dbce664..8ee757f43a 100644 --- a/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.scss +++ b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.scss @@ -30,6 +30,7 @@ font-size: 14px; } } + .input-container-header { position: absolute; top: 5px; @@ -41,6 +42,14 @@ font-size: 24px; } } + +.input-container-content { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; +} + p { color: grey; font-size: 12px; diff --git a/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/pages/feature-flag-root-page/feature-flag-root-page-content/feature-flag-root-section-card/feature-flag-root-section-card.component.html b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/pages/feature-flag-root-page/feature-flag-root-page-content/feature-flag-root-section-card/feature-flag-root-section-card.component.html index c7c574f264..36dc297154 100644 --- a/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/pages/feature-flag-root-page/feature-flag-root-page-content/feature-flag-root-section-card/feature-flag-root-section-card.component.html +++ b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/pages/feature-flag-root-page/feature-flag-root-page-content/feature-flag-root-section-card/feature-flag-root-section-card.component.html @@ -14,6 +14,7 @@ [showPrimaryButton]="true" [primaryButtonText]="'feature-flags.add-feature-flag.text' | translate" [menuButtonItems]="menuButtonItems" + [showMenuButton]="true" [isSectionCardExpanded]="isSectionCardExpanded" (primaryButtonClick)="onAddFeatureFlagButtonClick()" (menuButtonItemClick)="onMenuButtonItemClick($event)" diff --git a/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/pages/feature-flag-root-page/feature-flag-root-page-content/feature-flag-root-section-card/feature-flag-root-section-card.component.ts b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/pages/feature-flag-root-page/feature-flag-root-page-content/feature-flag-root-section-card/feature-flag-root-section-card.component.ts index e8525b1306..ae07c422d8 100644 --- a/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/pages/feature-flag-root-page/feature-flag-root-page-content/feature-flag-root-section-card/feature-flag-root-section-card.component.ts +++ b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/pages/feature-flag-root-page/feature-flag-root-page-content/feature-flag-root-section-card/feature-flag-root-section-card.component.ts @@ -98,7 +98,11 @@ export class FeatureFlagRootSectionCardComponent { } onMenuButtonItemClick(menuButtonItemName: string) { - console.log('onMenuButtonItemClick:', menuButtonItemName); + if (menuButtonItemName === 'Import Feature Flag') { + this.dialogService.openImportFeatureFlagModal(); + } else if (menuButtonItemName === 'Export All Feature Flags') { + console.log('onMenuButtonItemClick:', menuButtonItemName); + } } onSectionCardExpandChange(isSectionCardExpanded: boolean) { From 5b000680fbed7f4c013162c27008ee8c3d8ee458 Mon Sep 17 00:00:00 2001 From: Khanjan Dalwadi <17khanjan@gmail.com> Date: Mon, 1 Jul 2024 11:34:30 +0530 Subject: [PATCH 3/3] Made state variables as BehaviorSubjects and removed duplicate code --- .../import-feature-flag-modal.component.html | 8 +-- .../import-feature-flag-modal.component.ts | 61 ++++++++----------- .../projects/upgrade/src/assets/i18n/en.json | 1 + 3 files changed, 32 insertions(+), 38 deletions(-) diff --git a/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.html b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.html index 6e313786a3..259e49ebe8 100644 --- a/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.html +++ b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.html @@ -4,7 +4,7 @@ [cancelBtnLabel]="data.cancelBtnLabel" [primaryActionBtnLabel]="data.primaryActionBtnLabel" [primaryActionBtnColor]="data.primaryActionBtnColor" - [primaryActionBtnDisabled$]="isImportActionBtnDisabled" + [primaryActionBtnDisabled]="isImportActionBtnDisabled | async" >
close
-
+
insert_drive_file

{{ fileName }}

@@ -31,7 +31,7 @@

- The Feature Flag JSON file should include the required properties for it to be imported. + {{ 'feature-flags.import-feature-flag.message.text' | translate }} Learn More

diff --git a/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.ts b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.ts index 0d2d2395cb..e9cb49b01a 100644 --- a/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.ts +++ b/frontend/projects/upgrade/src/app/features/dashboard/feature-flags/modals/import-feature-flag-modal/import-feature-flag-modal.component.ts @@ -3,7 +3,7 @@ import { CommonModalComponent } from '../../../../../shared-standalone-component import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; import { CommonModalConfig } from '../../../../../shared-standalone-component-lib/components/common-modal/common-modal-config'; import { FeatureFlagsService } from '../../../../../core/feature-flags/feature-flags.service'; -import { BehaviorSubject, Observable, Subscription, combineLatest, map } from 'rxjs'; +import { BehaviorSubject } from 'rxjs'; import { CommonModule } from '@angular/common'; import { SharedModule } from '../../../../../shared/shared.module'; @@ -12,73 +12,66 @@ import { SharedModule } from '../../../../../shared/shared.module'; standalone: true, imports: [CommonModalComponent, CommonModule, SharedModule], templateUrl: './import-feature-flag-modal.component.html', - styleUrl: './import-feature-flag-modal.component.scss', + styleUrls: ['./import-feature-flag-modal.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) export class ImportFeatureFlagModalComponent { @ViewChild('fileInput') fileInput: ElementRef; isImportActionBtnDisabled = new BehaviorSubject(true); - isDragOver = false; - fileName: string | null = null; + isDragOver = new BehaviorSubject(false); + fileName = new BehaviorSubject(null); constructor( @Inject(MAT_DIALOG_DATA) - public data: CommonModalConfig & { flagName: string; flagId: string }, + public data: CommonModalConfig, public dialog: MatDialog, - private featureFlagsService: FeatureFlagsService, public dialogRef: MatDialogRef ) {} - onDragOver(event: DragEvent): void { + onDragOver(event: DragEvent) { event.preventDefault(); event.stopPropagation(); - this.isDragOver = true; + this.isDragOver.next(true); } - onDragLeave(event: DragEvent): void { + onDragLeave(event: DragEvent) { event.preventDefault(); event.stopPropagation(); - this.isDragOver = false; + this.isDragOver.next(false); } - onDrop(event: DragEvent): void { + onDrop(event: DragEvent) { event.preventDefault(); event.stopPropagation(); - this.isDragOver = false; + this.isDragOver.next(false); const files = event.dataTransfer?.files; if (files && files.length > 0) { - const file = files[0]; - if (file.type === 'application/json') { - this.fileName = file.name; - this.isImportActionBtnDisabled.next(false); - this.handleFileInput(file); - } else { - alert('Please upload a valid JSON file.'); - this.fileName = null; - this.isImportActionBtnDisabled.next(true); - } + this.processFile(files[0]); } } - onFileSelected(event: Event): void { + onFileSelected(event: Event) { const input = event.target as HTMLInputElement; if (input.files && input.files.length > 0) { - const file = input.files[0]; - if (file.type === 'application/json') { - this.fileName = file.name; - this.isImportActionBtnDisabled.next(false); - this.handleFileInput(file); - } else { - alert('Please upload a valid JSON file.'); - this.fileName = null; - this.isImportActionBtnDisabled.next(true); - } + this.processFile(input.files[0]); } } - handleFileInput(file: File): void { + processFile(file: File) { + if (file.type === 'application/json') { + this.fileName.next(file.name); + this.isImportActionBtnDisabled.next(false); + this.handleFileInput(file); + } else { + alert('Please upload a valid JSON file.'); + this.fileName.next(null); + this.isImportActionBtnDisabled.next(true); + } + } + + handleFileInput(file: File) { const reader = new FileReader(); reader.onload = (e: any) => { const jsonContent = e.target.result; diff --git a/frontend/projects/upgrade/src/assets/i18n/en.json b/frontend/projects/upgrade/src/assets/i18n/en.json index c646543e96..7c1bde17b1 100644 --- a/frontend/projects/upgrade/src/assets/i18n/en.json +++ b/frontend/projects/upgrade/src/assets/i18n/en.json @@ -388,6 +388,7 @@ "feature-flags.enable.text": "Enable", "feature-flags.add-feature-flag.text": "Add Feature Flag", "feature-flags.import-feature-flag.text": "Import Feature Flag", + "feature-flags.import-feature-flag.message.text": "The Feature Flag JSON file should include the required properties for it to be imported", "feature-flags.export-all-feature-flags.text": "Export All Feature Flags", "segments.title.text": "Segments", "segments.subtitle.text": "Define new segments to include or exclude from any experiment",