From fbc04e9e2886f9c3d9b0c95514afcd40fc2d8068 Mon Sep 17 00:00:00 2001 From: Vinay Sharma Date: Thu, 28 Apr 2022 05:39:13 +0530 Subject: [PATCH] added changes to fix the migration issue + check user conflicts Signed-off-by: Vinay Sharma --- .../src/app/entities/orgs/org.effects.ts | 7 - .../chef-server-details.component.html | 23 +-- .../chef-server-details.component.ts | 179 +++++++++--------- .../migration-slider.component.html | 19 +- .../migration-slider.component.scss | 8 + .../migration-slider.component.ts | 139 ++++++++++++-- 6 files changed, 245 insertions(+), 130 deletions(-) diff --git a/components/automate-ui/src/app/entities/orgs/org.effects.ts b/components/automate-ui/src/app/entities/orgs/org.effects.ts index 53e79dc7ceb7..15c4ba849019 100644 --- a/components/automate-ui/src/app/entities/orgs/org.effects.ts +++ b/components/automate-ui/src/app/entities/orgs/org.effects.ts @@ -290,11 +290,4 @@ export class OrgEffects { catchError((error: HttpErrorResponse) => observableOf(new CheckUserFailure(error))))))); - CheckUserSuccess = createEffect(() => - this.actions$.pipe( - ofType(OrgActionTypes.CHECK_USER_SUCCESS), - map(({ payload: { user } }) => new CreateNotification({ - type: Type.error, - message: `Could not use ${user} user name.` - })))); } diff --git a/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.html b/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.html index 22448e9ba8b8..0269db761177 100644 --- a/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.html +++ b/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.html @@ -48,11 +48,7 @@
  • Last Migration Status @@ -63,7 +59,7 @@ - + warning Migration failed, migration step not completed! @@ -73,7 +69,7 @@ - + warning Last migration cancelled! @@ -84,8 +80,8 @@ - Sync In Progress - + Sync In Progress + Loading.... - -- + Loading.... + --
  • diff --git a/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.ts b/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.ts index 14c768132fab..cfd25da84d9e 100644 --- a/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.ts +++ b/components/automate-ui/src/app/modules/infra-proxy/chef-server-details/chef-server-details.component.ts @@ -3,7 +3,7 @@ import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { MatOptionSelectionChange } from '@angular/material/core/option'; import { Router } from '@angular/router'; import { Store } from '@ngrx/store'; -import { Subject, combineLatest, Subscription, interval } from 'rxjs'; +import { Subject, combineLatest, Subscription } from 'rxjs'; import { filter, pluck, takeUntil } from 'rxjs/operators'; import { identity, isNil } from 'lodash/fp'; import { NgrxStateAtom } from 'app/ngrx.reducers'; @@ -101,7 +101,7 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { public webuiKey: WebUIKey; public updateWebUIKeySuccessful = false; - // used for the migration + // used for the preview migration step public uploadZipForm: FormGroup; public isUploaded = false; public migrationStatus: MigrationStatus; @@ -109,24 +109,29 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { public stepsCompleted: string; public totalMigrationSteps = 13; public migrationStepValue: number; - public migrationfailed = false; - public migrationCompleted = false; + + // migration steps + public migrationLoading = false; public migrationInProgress = false; - public migrationLoading = true; - public migrationStarted = false; public migrationIsInPreview = false; + public migrationCompleted = false; + public migrationFailed = false; + public migrationCancelled = false; public migrationNotRunning = true; + + // migration values public migration_id = ''; - public migration_type: string; - public cancelMigrationInProgress = false; - public canceMigrationSuccessful = false; - public isCancelled = false; - public previewDataLoaded = false; + public migration_type = ''; + public migration_status = ''; + + // migration preview data public previewData; public isPreview = false; public confirmPreviewSuccessful = false; + public cancelMigrationSuccessful = false; public confirmPreviewsubmit = false; public checkMigrationStatus: Subscription; + public myInterval: ReturnType; public orgDataLoaded = false; public orgData: Org[] = []; public migrationSteps: Record = { @@ -290,9 +295,8 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { takeUntil(this.isDestroyed), filter(state => !pending(state))) .subscribe((state) => { - this.cancelMigrationInProgress = true; - this.canceMigrationSuccessful = (state === EntityStatus.loadingSuccess); - if (this.canceMigrationSuccessful) { + this.cancelMigrationSuccessful = (state === EntityStatus.loadingSuccess); + if (this.cancelMigrationSuccessful) { setTimeout(() => { this.migrationIsCancelled(); }, 1000); } else { setTimeout(() => { this.migrationIsInProcess(); }, 1000); @@ -308,8 +312,6 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { if (previewStatusSt === EntityStatus.loadingSuccess && !isNil(previewState)) { this.previewData = previewState; this.isPreview = true; - } else if (previewStatusSt === EntityStatus.loadingFailure) { - this.previewDataLoaded = false; } }); @@ -322,10 +324,10 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { if (this.confirmPreviewSuccessful) { this.confirmPreviewsubmit = true; this.migrationLoading = false; - setTimeout(() => { this.migrationIsCompleted(); }, 1000); this.orgsListLoading = true; setTimeout( () => { - this.getServerAndOrgs(); + // call to get the list of orgs + this.getListofOrgs(this.server_id); }, 2000 ); } else { this.confirmPreviewsubmit = false; @@ -334,12 +336,13 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { // Get the running migration status this.callToGetMigrationStatus(); - } ngOnDestroy(): void { - this.isDestroyed.next(true); + this.isDestroyed.next(); this.isDestroyed.complete(); + this.checkMigrationStatus.unsubscribe(); + clearInterval(this.myInterval); } onSelectedTab(event: { target: { value: ChefServerTabName } }) { @@ -358,13 +361,6 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { // call to get the list of orgs this.getListofOrgs(this.server_id); - if (this.orgs.length > 0 ) { - if (!this.migrationInProgress) { - this.migrationIsCompleted(); - } - this.migrationNotRunning = false; - } - if (this.migration_id !== '') { setTimeout(() => { this.migrationProcessStarted(); }, 1000); this.getMigrationStatus(this.migration_id); @@ -376,12 +372,6 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { this.validateWebUIKey(this.server); } }, 1000); - - // relaod the orgs in case of orgs are not loaded - if ( this.migrationCompleted && this.orgs.length <= 0) { - this.getServerAndOrgs(); - this.migrationIsCompleted(); - } } public startOrgDelete($event: MatOptionSelectionChange, org: Org): void { @@ -415,7 +405,8 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { this.ipForm.controls['ip_address'].setValue(this.server.ip_address); this.isServerLoaded = true; this.migrationLoading = false; - this.migration_id = this.server.migration_id; + this.migration_id = this.server?.migration_id; + console.log(this.migration_id); this.migration_type = this.server.migration_type; } }); @@ -477,119 +468,129 @@ export class ChefServerDetailsComponent implements OnInit, OnDestroy { } // get migration status - private getMigrationStatus(migration_id: string): void { + public getMigrationStatus(migration_id: string): void { this.store.dispatch(new GetMigrationStatus(migration_id)); - combineLatest([ + this.checkMigrationStatus = combineLatest([ this.store.select(migrationStatus), this.store.select(getMigrationStatus) - ]).pipe(takeUntil(this.isDestroyed)) - .subscribe(([migrationSt, getMigrationState]) => { - if (migrationSt === EntityStatus.loadingSuccess && !isNil(getMigrationState)) { - this.migrationStatus = getMigrationState; + ]).pipe( + takeUntil(this.isDestroyed), + filter(([getMigrationSt, _migrationState]) => + getMigrationSt === EntityStatus.loadingSuccess), + filter(([_getMigrationSt, migrationState]) => + !isNil(migrationState)) + ).subscribe(([_getMigrationSt, migrationState]) => { + if (!isNil(migrationState)) { + this.migrationStatus = migrationState; this.migration_type = this.migrationStatus.migration_type; - const migration_status = this.migrationStatus.migration_status; - this.migrationNotRunning = false; - if (migration_status === 'Completed' || migration_status === 'In Progress') { + this.migration_status = this.migrationStatus.migration_status; + + // case for the migration is in progress/creating_peview + if (this.migration_status === 'Completed' || this.migration_status === 'In Progress') { this.migrationStepValue = this.getKeyByValue(this.migrationSteps, this.migration_type); this.migrationStatusPercentage = Number((this.migrationStepValue / this.totalMigrationSteps) * 100); - setTimeout(() => { this.migrationIsInProcess(); }, 1000); + this.migrationIsInProcess(); this.stepsCompleted = this.migrationStepValue.toFixed(0) + '/' + '13'; if (this.migration_type === 'Creating Preview' - && this.confirmPreviewsubmit === false - && this.isCancelled === false) { - setTimeout(() => { this.migrationInPreview(); }, 1000); + && this.migrationCancelled === false + && this.migrationFailed === false) { + this.migrationInPreview(); } + } - if (this.migration_type === 'Migration Completed') { - setTimeout(() => { - this.migrationIsCompleted(); - this.checkMigrationStatus.unsubscribe(); - }, 1000); - } + // case for the migration completed + if (this.migration_type === 'Migration Completed' && this.migration_status === 'Completed') { + this.migrationIsCompleted(); + } - if (this.migration_type === 'Migration Cancelled' && this.canceMigrationSuccessful) { - setTimeout(() => { - this.migrationIsCancelled(); - this.checkMigrationStatus.unsubscribe(); - }, 1000); - } - } else { - this.migrationfailed = true; - this.migrationCompleted = false; - this.checkMigrationStatus.unsubscribe(); + // case for the migration cancelled + if (this.migration_type === 'Migration Cancelled' && this.cancelMigrationSuccessful) { + this.migrationIsCancelled(); + } + + // case for the migration failed + if (this.migration_status === 'Failed' && + this.migration_type === 'Migration Completed') { + this.migrationIsFailed(); } } }); + + if (this.migration_type !== '' && this.migration_status !== '') { + this.checkMigrationStatus.unsubscribe(); + } } public migrationProcessStarted() { - this.migrationStarted = true; this.migrationInProgress = true; this.migrationIsInPreview = false; this.migrationCompleted = false; - this.migrationfailed = false; - this.isCancelled = false; + this.migrationFailed = false; + this.migrationCancelled = false; + this.migrationNotRunning = false; } public migrationIsInProcess(): void { - this.checkMigrationStatus.unsubscribe(); - // Get the running migration status - this.callToGetMigrationStatus(); - - this.migrationStarted = true; this.migrationInProgress = true; this.migrationIsInPreview = false; this.migrationCompleted = false; - this.migrationfailed = false; - this.isCancelled = false; + this.migrationFailed = false; + this.migrationCancelled = false; + this.migrationNotRunning = false; } public migrationInPreview(): void { - this.migrationStarted = true; this.migrationInProgress = true; this.migrationIsInPreview = true; this.migrationCompleted = false; - this.migrationfailed = false; - this.isCancelled = false; + this.migrationFailed = false; + this.migrationCancelled = false; + this.migrationNotRunning = false; } public migrationIsCompleted(): void { - if (!this.isCancelled) { - this.migrationStarted = true; + if (!this.migrationCancelled) { this.migrationInProgress = false; this.migrationIsInPreview = false; this.migrationCompleted = true; - this.migrationfailed = false; - this.isCancelled = false; + this.migrationFailed = false; + this.migrationCancelled = false; + this.migrationNotRunning = true; + this.checkMigrationStatus.unsubscribe(); + clearInterval(this.myInterval); } } public migrationIsFailed(): void { - this.migrationStarted = true; this.migrationInProgress = false; this.migrationIsInPreview = false; this.migrationCompleted = false; - this.migrationfailed = true; - this.isCancelled = false; + this.migrationFailed = true; + this.migrationCancelled = false; + this.migrationNotRunning = true; + this.checkMigrationStatus.unsubscribe(); + clearInterval(this.myInterval); } public migrationIsCancelled(): void { - this.migrationStarted = true; this.migrationInProgress = false; this.migrationIsInPreview = false; this.migrationCompleted = false; - this.migrationfailed = false; - this.isCancelled = true; + this.migrationFailed = false; + this.migrationCancelled = true; + this.migrationNotRunning = true; + this.checkMigrationStatus.unsubscribe(); + clearInterval(this.myInterval); } public callToGetMigrationStatus() { - this.checkMigrationStatus = interval(4000).subscribe(() => { - if (this.migration_id !== '' && this.migrationStarted && this.migration_type !== 'Migration Completed') { + this.myInterval = setInterval(() => { + if (this.migration_id !== '' && this.migration_type !== 'Migration Completed') { this.getMigrationStatus(this.migration_id); } - }); + }, 5000); } public getKeyByValue(object: Record, value: string) { diff --git a/components/automate-ui/src/app/modules/infra-proxy/migration-slider/migration-slider.component.html b/components/automate-ui/src/app/modules/infra-proxy/migration-slider/migration-slider.component.html index de59c0d87b87..fc1724918c47 100644 --- a/components/automate-ui/src/app/modules/infra-proxy/migration-slider/migration-slider.component.html +++ b/components/automate-ui/src/app/modules/infra-proxy/migration-slider/migration-slider.component.html @@ -42,6 +42,10 @@

    You have the option to choose which users to migrate

    Conflicting Users {{conflictedUsers?.length || 0}} +
  • + Selected Users For Migration + {{selectedUsersData?.length || 0}} +
  • @@ -63,7 +67,7 @@

    You have the option to choose which users to migrate

    - + {{user.username}} @@ -72,19 +76,22 @@

    You have the option to choose which users to migrate

    {{user.automate_username}}
    - -

    +

    Warning. User already exists in Automate. This will overwrite this users IAM settings.

    @@ -96,7 +103,7 @@

    You have the option to choose which users to migrate

    Cancel Migration - + confirm Migration diff --git a/components/automate-ui/src/app/modules/infra-proxy/migration-slider/migration-slider.component.scss b/components/automate-ui/src/app/modules/infra-proxy/migration-slider/migration-slider.component.scss index 53cafa50f3ff..0126ce9da703 100644 --- a/components/automate-ui/src/app/modules/infra-proxy/migration-slider/migration-slider.component.scss +++ b/components/automate-ui/src/app/modules/infra-proxy/migration-slider/migration-slider.component.scss @@ -135,4 +135,12 @@ text-align: right; } } + + .user-exist-warning { + border: 1px solid rgba(220, 38, 127, 0.9); + } + + .warning-msg-hide { + display: none; + } } diff --git a/components/automate-ui/src/app/modules/infra-proxy/migration-slider/migration-slider.component.ts b/components/automate-ui/src/app/modules/infra-proxy/migration-slider/migration-slider.component.ts index f88ea50df48b..fd49db27924a 100644 --- a/components/automate-ui/src/app/modules/infra-proxy/migration-slider/migration-slider.component.ts +++ b/components/automate-ui/src/app/modules/infra-proxy/migration-slider/migration-slider.component.ts @@ -1,9 +1,11 @@ -import { Component, EventEmitter, HostBinding, Input, OnChanges, Output } from '@angular/core'; +import { Component, EventEmitter, HostBinding, Input, OnChanges, OnDestroy, Output } from '@angular/core'; import { FormBuilder, FormControl, FormGroup } from '@angular/forms'; -import { IdMapper } from 'app/helpers/auth/id-mapper'; -import { Utilities } from 'app/helpers/utilities/utilities'; +import { Subject } from 'rxjs'; +import { pending, EntityStatus } from 'app/entities/entities'; +import { filter, takeUntil } from 'rxjs/operators'; import { User } from '../../../entities/orgs/org.model'; import { CheckUser } from '../../../entities/orgs/org.actions'; +import { checkUserStatus } from 'app/entities/orgs/org.selectors'; import { Store } from '@ngrx/store'; import { NgrxStateAtom } from 'app/ngrx.reducers'; @@ -12,18 +14,21 @@ import { NgrxStateAtom } from 'app/ngrx.reducers'; templateUrl: './migration-slider.component.html', styleUrls: ['./migration-slider.component.scss'] }) -export class MigrationSliderComponent implements OnChanges { +export class MigrationSliderComponent implements OnChanges, OnDestroy { @Input() migrationID: string; @Input() isPreview: boolean; @Input() previewData; @Output() confirmPreview = new EventEmitter(); @Output() cancelMigration = new EventEmitter(); + private isDestroyed = new Subject(); public checkedUser = false; public migrationForm: FormGroup; public usersData: User[]; public selectedUsersData: User[] = []; public conflictedUsers: User[] = []; + public notReadyToConfirm = true; + public userExist: boolean; @HostBinding('class.active') isSlideOpen1 = false; constructor( @@ -52,6 +57,11 @@ export class MigrationSliderComponent implements OnChanges { this.migrationForm = new FormGroup(group); } + ngOnDestroy(): void { + this.isDestroyed.next(); + this.isDestroyed.complete(); + } + closeMigrationSlider() { this.toggleSlide(); } @@ -83,37 +93,132 @@ export class MigrationSliderComponent implements OnChanges { } else { this.selectedUsersData = []; } + this.checkNotreadyToConfirm(); } - selectedUser(event: any) { - const index = this.usersData.findIndex(x => x.username === event.target.value); - if (event.target.checked) { - this.selectedUsersData.push(this.usersData[index]); - } else { + selectedUser(event: Event, user: User) { + const checkBox = document.getElementById(user.email + '-chef-checkbox'); + const input = document.getElementById(user.email + '-input'); + const warning = document.getElementById(user.email + '-warning'); + console.log(event); + const index = this.usersData.findIndex(x => x.username === user.username); + if (checkBox.textContent === 'check') { this.selectedUsersData.forEach((value, i) => { - if (value.username === event.target.value) { + if (value.username === user.username) { this.selectedUsersData.splice(i, 1); } }); + if (user.is_conflicting) { + input.classList.remove('user-exist-warning'); + warning.classList.add('warning-msg-hide'); + } + } else { + this.selectedUsersData.push(this.usersData[index]); + warning.classList.remove('warning-msg-hide'); + this.callAndSetUserData(user); } } - handleNameInput(event: KeyboardEvent): void { - if (!Utilities.isNavigationKey(event)) { - this.migrationForm.controls.name.setValue( - IdMapper.transform(this.migrationForm.controls.name.value.trim())); + + handleName(event: Event, user: User): void { + this.callToCheckUsernameExist(event, user); + } + + callToCheckUsernameExist(event: Event, user: User) { + const checkBox = document.getElementById(user.email + '-chef-checkbox'); + console.log(event); + + if (checkBox.textContent === 'check') { + this.callAndSetUserData(user); } } - handleName(event: KeyboardEvent): void { - if ((event.target as HTMLInputElement).value !== '') { + callAndSetUserData(user: User) { + const input = document.getElementById(user.email + '-input'); + if ((input as HTMLInputElement).value !== '') { const payload = { - user: (event.target as HTMLInputElement).value + user: (input as HTMLInputElement).value }; this.store.dispatch(new CheckUser(payload)); + // check user status + this.store.select(checkUserStatus).pipe( + takeUntil(this.isDestroyed), + filter(state => !pending (state))) + .subscribe((state) => { + this.userExist = (state === EntityStatus.loadingSuccess); + }); + + if (this.userExist) { + input.classList.add('user-exist-warning'); + + const index = this.usersData.findIndex(x => x.username === user.username); + this.conflictedUsers.forEach((item: User) => { + if (item.username !== user.username) { + this.conflictedUsers.push(this.usersData[index]); + } + }); + + // uniq data for the conflcted users + this.conflictedUsers = [...new Set(this.conflictedUsers)]; + + this.selectedUsersData.forEach((item: User) => { + if (item.username === user.username) { + item.is_conflicting = true; + } + }); + + // uniq data for the selected users + this.selectedUsersData = [...new Set(this.selectedUsersData)]; + + this.usersData.forEach((item: User) => { + if (item.username === user.username) { + item.is_conflicting = true; + } + }); + + // uniq data for the users data + this.usersData = [...new Set(this.usersData)]; + + } else { + input.classList.remove('user-exist-warning'); + this.conflictedUsers.forEach((value, i) => { + if (value.username === user.username) { + this.conflictedUsers.splice(i, 1); + } + }); + + // uniq data for the conflcted users + this.conflictedUsers = [...new Set(this.conflictedUsers)]; + + this.selectedUsersData.forEach((item: User) => { + if (item.username === user.username) { + item.is_conflicting = false; + } + }); + + // uniq data for the selected users + this.selectedUsersData = [...new Set(this.selectedUsersData)]; + + this.usersData.forEach((item: User) => { + if (item.username === user.username) { + item.is_conflicting = false; + } + }); + + // uniq data for the users data + this.usersData = [...new Set(this.usersData)]; + } + + this.checkNotreadyToConfirm(); } } + checkNotreadyToConfirm() { + const selectedConflictUsersCount = + this.selectedUsersData.filter(e => e.is_conflicting === true).length; + this.notReadyToConfirm = selectedConflictUsersCount === 0 ? false : true; + } + onChangeEvent(event: any) { const username = event.target.dataset.username; const index = this.usersData.findIndex(x => x.username === username);