This is an automated email from the ASF dual-hosted git repository. dgnatyshyn pushed a commit to branch DLAB-1750 in repository https://gitbox.apache.org/repos/asf/incubator-dlab.git
commit 52ca2c6f0e2bb8bc1641e131c54aa85e1ff98d39 Author: Dmytro_Gnatyshyn <di1...@ukr.net> AuthorDate: Thu Jul 23 19:06:03 2020 +0300 [DLAB-1943]: Fixed issues for library page --- .../install-libraries.component.html | 156 +++++++++++++++------ .../install-libraries.component.scss | 65 +++++---- .../install-libraries.component.ts | 153 ++++++++++---------- .../src/main/resources/webapp/src/styles.scss | 3 +- 4 files changed, 233 insertions(+), 144 deletions(-) diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.html index 2146f5d..96f2bd6 100644 --- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.html +++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.html @@ -52,53 +52,119 @@ </div> </div> </div> - <div class="m-top-20"> + <div class="m-top-20" *ngIf="group !== 'java'; else javaGroup"> <div class="control-group constol-select"> <label class="label">Library name</label> - <div class="control"> - <input type="text" [placeholder]="'Enter library name'" [(ngModel)]="lib.name" [disabled]="!group" matInputb> + <div class="control control-relative"> + <span class="other-message" *ngIf="group === 'others'">Other group can include libs from Python 2 and Python 3 groups</span> + <input + type="text" [placeholder]="'Enter library name'" + [(ngModel)]="lib.name" + [disabled]="!group" + [matAutocomplete]="auto" + [formControl]="libSearch" + #trigger="matAutocompleteTrigger" + (keyup.enter)="addLibrary(lib)" + > </div> + <mat-autocomplete #auto="matAutocomplete" class="suggestions" > + <ng-template ngFor let-item [ngForOf]="filteredList" let-i="index" *ngIf="!selectedLib"> + <mat-option > + <div class="option" (click)="selectLibrary(item);$event.stopPropagation()" [ngClass]="{'not-allow': item.isInSelectedList}"> + <a *ngIf="!item.isInSelectedList"> + <span [innerHTML]="item.name | highlight:query"></span> + </a> + <span *ngIf="item.isInSelectedList">{{ item.name }} + <span *ngIf="item.version && item.version !== 'N/A' && item.isInstalled && !item.isInSelectedList">{{ item.version }}</span> + </span> + <strong *ngIf="item.isInSelectedList">selected + <i class="material-icons">done</i> + </strong> + <strong *ngIf="item.isInstalled && !item.isInSelectedList">installed + <i class="material-icons">done</i> + </strong> + </div> + </mat-option> + </ng-template> + <mat-option *ngIf="model.isEmpty(filteredList) && !validity_format"> + <span class="configuring">No matches found</span> + </mat-option> + <mat-option *ngIf="validity_format?.length > 0"> + <span class="configuring" >{{ validity_format }}</span > + </mat-option> + </mat-autocomplete> </div> <div class="control-group control-select"> <label class="label">Library version</label> - <div class="control"> - <input type="text" [placeholder]="'Enter library version (optional)'" [(ngModel)]="lib.version" [disabled]="!lib.name" [matAutocomplete]="auto" #trigger="matAutocompleteTrigger" [formControl]="libSearch"> - <mat-autocomplete #auto="matAutocomplete" class="suggestions" >--> - <ng-template ngFor let-item [ngForOf]="filteredList" let-i="index" *ngIf="query.indexOf(':') === -1"> - <mat-option [ngClass]="{ 'not-allowed': isDuplicated(item) }"> - <div class="option" (click)="selectLibrary(item)"> - <a *ngIf="!isDuplicated(item)"> - <span [innerHTML]="item.name | highlight:query"></span> - <!-- <span *ngIf="item.version && item.version !== 'N/A'">{{ item.version }}</span>--> - </a> - <span *ngIf="isInSelectedList || isInstalled">{{ item.name }} - <span *ngIf="item.version && item.version !== 'N/A'">{{ item.version }}</span> - </span> - - <strong *ngIf="isInSelectedList">selected - <i class="material-icons">done</i> - </strong> - <strong *ngIf="isInstalled">installed - <i class="material-icons">done</i> - </strong> - </div> - </mat-option> - </ng-template> -<!-- <mat-option *ngIf="model.isEmpty(filteredList) && !validity_format && query.indexOf(':') === -1">--> -<!-- <span class="configuring">No matches found</span>--> -<!-- </mat-option>--> -<!-- <mat-option *ngIf="validity_format?.length > 0">--> -<!-- <span class="configuring" *ngIf="query.indexOf(':') === -1">{{ validity_format }}</span >--> -<!-- </mat-option>--> - </mat-autocomplete> - <span class="error-message" *ngIf="!group && libSearch.value">Group field is required. Please choose appropriate group.</span> + <div class="control control-relative"> + <input type="text" [placeholder]="'Enter library version (optional)'" [(ngModel)]="lib.version" [disabled]="!lib.name" (keyup.enter)="addLibrary(lib)"> + <span class="plus-icon" + [ngClass]="{'not-allow': !this.selectedLib || this.selectedLib?.isInSelectedList}" + matTooltip="Library is in selected list" matTooltipPosition="above" [matTooltipDisabled]="!this.selectedLib?.isInSelectedList" + > + <mat-icon (click)="addLibrary(lib)" [ngClass]="{'not-allowed': !this.selectedLib || this.selectedLib?.isInSelectedList }">add</mat-icon> + </span> </div> </div> - <mat-icon class="plus-icon" (click)="addLibrary(lib)" [ngClass]="{'not-allow': !lib.name}">add</mat-icon> </div> - <p class="other-message"> - <span *ngIf="group === 'others'">Other group can include libs from Python 2 and Python 3 groups</span> - </p> + + <ng-template #javaGroup> + <div class="m-top-20"> + <div class="control-group constol-select java-library-search"> + <label class="label">Library</label> + <div class="control control-relative"> + <span class="other-message" *ngIf="lib.name.length && !this.selectedLib">groupId:artifactId:versionId</span> + <input + type="text" [placeholder]="'Enter library name in <groupId>:<artifactId>:<versionId> format'" + [(ngModel)]="lib.name" + [disabled]="!group" + [matAutocomplete]="auto" + [formControl]="libSearch" + #trigger="matAutocompleteTrigger" + (keyup.enter)="addLibrary(lib)" + > + <span + class="plus-icon" + [ngClass]="{'not-allow': !this.selectedLib || this.selectedLib?.isInSelectedList}" + matTooltip="Library is in selected list" matTooltipPosition="above" [matTooltipDisabled]="!this.selectedLib?.isInSelectedList" + > + <mat-icon (click)="addLibrary(lib)" (keyup.enter)="addLibrary(lib)" [ngClass]="{'not-allowed': !this.selectedLib || this.selectedLib?.isInSelectedList}">add</mat-icon> + </span> + </div> + <mat-autocomplete #auto="matAutocomplete" class="suggestions"> + <ng-template ngFor let-item [ngForOf]="filteredList" let-i="index" *ngIf="!selectedLib"> + <mat-option > + <div class="option" (click)="selectLibrary(item);$event.stopPropagation()" [ngClass]="{'not-allow': item.isInSelectedList}"> + <a *ngIf="!item.isInSelectedList"> + <span [innerHTML]="item.name + ':' + item.version | highlight:query"> + <span>{{ item.version }}</span> + </span> + </a> + <span *ngIf="item.isInSelectedList">{{ item.name }} + <span *ngIf="item.version && item.version !== 'N/A'">{{ item.version }}</span> + </span> + <strong *ngIf="item.isInSelectedList">selected + <i class="material-icons">done</i> + </strong> + <strong *ngIf="item.isInstalled && !item.isInSelectedList">installed + <i class="material-icons">done</i> + </strong> + </div> + </mat-option> + </ng-template> + <mat-option *ngIf="model.isEmpty(filteredList) && !validity_format"> + <span class="configuring">No matches found</span> + </mat-option> + <mat-option *ngIf="validity_format?.length > 0"> + <span class="configuring" >{{ validity_format }}</span > + </mat-option> + </mat-autocomplete> + </div> + </div> + </ng-template> +<!-- <p class="other-message">--> +<!-- --> +<!-- </p>--> <div class="search"> <!-- <mat-form-field class="chip-list">--> <!-- <input--> @@ -266,9 +332,11 @@ <!-- </div>--> <ng-container *ngFor="let lib of filtredNotebookLibs"> <mat-list-item class="table-item"> - <div class="lib-name ellipsis"> - <strong>{{ lib.name }}</strong> - <span *ngIf="lib.version && lib.version !== 'N/A'">{{ lib.version }}</span> + <div class="lib-name lib-name-col ellipsis" > + <span [matTooltip]="lib.name + ' ' + lib.version" matTooltipPosition="above" class="lib-name-wrapper"> + <span class="stong" >{{ lib.name }}</span> + <span *ngIf="lib.version && lib.version !== 'N/A'">{{ lib.version }}</span> + </span> </div> <div class="lib-group-col">{{ groupsListMap[lib.group] }}</div> <div class="st-group"> @@ -276,8 +344,8 @@ <div class="wrap-col"> <div class="lib-destination-col">{{ item.resource }}</div> <div class="lib-resource-type-col">{{ item.resourceType }}</div> - <div class="lib-status-col" ngClass="{{ item.status.toLowerCase() || 'failed' }}">{{ item.status }} - <div class="warn-action" *ngIf="(item.status === 'failed' || item.status === 'invalid version') && notebook?.status === 'running'"> + <div class="lib-status-col" ngClass="{{ item.status.toLowerCase() || 'failed' }}">{{ item.status.replace('_', ' ') }} + <div class="warn-action" *ngIf="(item.status === 'failed' || item.status.toLowerCase() === 'invalid_version') && notebook?.status === 'running'"> <div *ngIf="!item.available_versions"> <span *ngIf="!installingInProgress" (click)="reinstallLibrary(item, lib)" matTooltip="Retry installation" matTooltipPosition="above"> <i class="material-icons">replay</i> @@ -291,7 +359,7 @@ <i class="material-icons">error_outline</i> </div> <div class="lib-error" - *ngIf="item.status === 'invalid version' && item.available_versions?.length" class="lib-error" + *ngIf="item.status.toLowerCase() === 'invalid_version' && item.available_versions?.length" class="lib-error" (click)="openLibInfo(item, 'available');$event.stopPropagation()" matTooltip="Show available version" matTooltipPosition="above" > diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.scss b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.scss index 044ff8f..86cd434 100644 --- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.scss +++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.scss @@ -184,19 +184,28 @@ ul.resources{ width: 50%; padding-bottom: 0; - .label { - width: 20%; + &.java-library-search{ + width: 100%; + + .label{ + width: 10%; + } + + .control{ + width: 85%; + } } - } - .other-message{ - height: 22px; - display: flex; - align-items: center; + .control{ + width: 70%; - span{ - font-size: 12px; - color: $link-color; + input{ + font-size: 14px; + } + } + + .label { + width: 20%; } } @@ -205,6 +214,7 @@ ul.resources{ padding-bottom: 0; flex-direction: column; box-shadow: 0 3px 1px -2px rgba(0, 0, 0, .2), 0 2px 2px 0 rgba(0, 0, 0, .14), 0 1px 5px 0 rgba(0, 0, 0, .12); + margin-top: 25px; .mat-form-field-flex { padding-left: 15px; @@ -217,7 +227,7 @@ ul.resources{ &.mat-form-field { width: 100%; - //padding: 5px 20px; + .mat-form-field-infix{ display: flex; } @@ -287,7 +297,7 @@ ul.resources{ } .list-selected { - padding: 0 5px; + padding: 10px; font-family: 'Open Sans', sans-serif; height: 130px; overflow-y: auto; @@ -323,10 +333,6 @@ mat-chip.mat-chip:not(.mat-basic-chip) { line-height: 40px; } -.list-header+div{ - padding-left: 5px; -} - .mat-dialog-container { position: relative; } @@ -355,18 +361,17 @@ mat-chip.mat-chip:not(.mat-basic-chip) { } } } - .lib-col{ - padding-left: 4px; - - } .lib-name { width: 27%; - &.lib-input{ + &-col{ + display: flex; } .lib-name-wrapper{ + overflow: hidden; display: block; + text-overflow: ellipsis; } strong { @@ -552,19 +557,29 @@ mat-chip.mat-chip:not(.mat-basic-chip) { line-height: 26px; } -.m-top-20{ +.control-relative{ position: relative; - .plus-icon{ + + .plus-icon { position: absolute; - right: 70px; + right: -40px; top: 5px; color: #35afd5; font-size: 27px; cursor: pointer; - &.not-allow{ + + &.not-allow { color: lightgray; } } + + .other-message{ + position: absolute; + font-size: 12px; + color: $link-color; + top: 40px; + left: 12px; + } } @media screen and (min-width: 1281px) { diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.ts index ed5fa6d..97e94f7 100644 --- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.ts +++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/install-libraries/install-libraries.component.ts @@ -18,7 +18,7 @@ */ -import {Component, OnInit, ViewChild, ViewEncapsulation, ChangeDetectorRef, Inject, OnDestroy} from '@angular/core'; +import {Component, OnInit, ViewChild, ViewEncapsulation, ChangeDetectorRef, Inject, OnDestroy, AfterViewInit} from '@angular/core'; import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; import { FormControl } from '@angular/forms'; import { ToastrService } from 'ngx-toastr'; @@ -45,7 +45,7 @@ export class InstallLibrariesComponent implements OnInit, OnDestroy { public model: InstallLibrariesModel; public notebook: any; - public filteredList: any; + public filteredList: any = []; public groupsList: Array<string>; public notebookLibs: Array<any> = []; public notebookFailedLibs: Array<any> = []; @@ -57,7 +57,6 @@ export class InstallLibrariesComponent implements OnInit, OnDestroy { public uploading: boolean = false; public libs_uploaded: boolean = false; public validity_format: string = ''; - public isInstalled: boolean = false; public isInSelectedList: boolean = false; public installingInProgress: boolean = false; @@ -84,7 +83,9 @@ export class InstallLibrariesComponent implements OnInit, OnDestroy { @ViewChild('trigger', { static: false }) matAutoComplete; public isLibInfoOpened = { }; private isLibExist: boolean; - lib: Library = {name: '', version: ''}; + public lib: Library = {name: '', version: ''}; + public javaLib: {group, artifact, version} = {group: '', artifact: '', version: ''}; + private selectedLib: any = null; constructor( @Inject(MAT_DIALOG_DATA) public data: any, @@ -99,10 +100,13 @@ export class InstallLibrariesComponent implements OnInit, OnDestroy { ngOnInit() { this.open(this.data); - this.libSearch.valueChanges.pipe( + this.libSearch.disable(); + this.libSearch.valueChanges + .pipe( debounceTime(1000)) .subscribe(newValue => { - this.query = newValue || ''; + this.query = newValue; + this.isDuplicated(this.lib); this.filterList(); }); } @@ -146,7 +150,7 @@ export class InstallLibrariesComponent implements OnInit, OnDestroy { public filterList(): void { this.validity_format = ''; - (this.lib.name.length >= 2 && this.group) ? this.getFilteredList() : this.filteredList = null; + (this.query && this.query.length >= 2 && this.group && !this.selectedLib) ? this.getFilteredList() : this.filteredList = null; } public filterGroups(groupsList) { @@ -160,6 +164,7 @@ export class InstallLibrariesComponent implements OnInit, OnDestroy { public onUpdate($event) { if ($event.model.type === 'group_lib') { + this.libSearch.enable(); this.group = $event.model.value; } else if ($event.model.type === 'destination') { this.resetDialog(); @@ -169,6 +174,7 @@ export class InstallLibrariesComponent implements OnInit, OnDestroy { : this.model.computational_name = null; this.uploadLibGroups(); this.getInstalledLibsByResource(); + this.libSearch.disable(); } this.filterList(); } @@ -178,37 +184,50 @@ export class InstallLibrariesComponent implements OnInit, OnDestroy { } public isDuplicated(item) { - const select = { group: this.group, name: item.name, version: item.version }; - - this.isInSelectedList = this.model.selectedLibs.filter(el => JSON.stringify(el) === JSON.stringify(select)).length > 0; - - if (this.destination && this.destination.libs) - this.isInstalled = this.destination.libs.findIndex(libr => { - return select.group !== 'java' - ? select.name === libr.name && select.group === libr.group && select.version === libr.version - : select.name === libr.name && select.group === libr.group; - }) >= 0; + if (this.filteredList) { + if (this.group !== 'java') { + this.selectedLib = this.filteredList.find(lib => lib.name === item.name); + } else { + this.selectedLib = this.filteredList.find(lib => { + return lib.name === item.name.substring(0, item.name.lastIndexOf(':')); + }); + } + } else { + this.selectedLib = null; + } - return this.isInSelectedList || this.isInstalled; + if (this.selectedLib) { + this.filteredList = null; + } } public addLibrary(item): void { - this.model.selectedLibs.push({ group: this.group, name: item.name, version: item.version || 'N/A' }); - this.query = ''; - this.libSearch.setValue(''); - this.lib = {name: '', version: ''}; - this.filteredList = null; + if (this.selectedLib && !this.selectedLib.isInSelectedList) { + this.model.selectedLibs.push({ group: this.group, name: item.name, version: item.version || 'N/A' }); + this.query = ''; + this.libSearch.setValue(''); + this.lib = {name: '', version: ''}; + this.filteredList = null; + } } public selectLibrary(item): void { - // this.model.selectedLibs.push({ group: this.group, name: item.name, version: item.version }); - // this.query = ''; - this.libSearch.setValue(item.name); - this.filteredList = null; + if (item.isInSelectedList) { + return; + } + if (this.group === 'java') { + this.libSearch.setValue(item.name + ':' + item.version); + this.lib.name = item.name + ':' + item.version; + } else { + this.libSearch.setValue(item.name); + this.lib.name = item.name; + } + this.matAutoComplete.closePanel(); } public removeSelectedLibrary(item): void { this.model.selectedLibs.splice(this.model.selectedLibs.indexOf(item), 1); + this.getMatchedLibs(); } public open(notebook): void { @@ -238,7 +257,7 @@ export class InstallLibrariesComponent implements OnInit, OnDestroy { public isInstallingInProgress(): void { this.installingInProgress = this.notebookLibs.some(lib => lib.filteredStatus.some(status => status.status === 'installing')); if (this.installingInProgress) { - clearTimeout(this.loadLibsTimer); + window.clearTimeout(this.loadLibsTimer); this.loadLibsTimer = window.setTimeout(() => this.getInstalledLibrariesList(), 10000); } } @@ -307,7 +326,20 @@ export class InstallLibrariesComponent implements OnInit, OnDestroy { if (this.group === 'java') { this.model.getDependencies(this.query) .subscribe( - lib => this.filteredList = [lib], + libs => { + this.filteredList = [libs]; + this.filteredList.forEach(lib => { + lib.isInSelectedList = this.model.selectedLibs.some(el => lib.name === el.name.substring(0, el.name.lastIndexOf(':'))); + lib.isInstalled = this.notebookLibs.some(libr => { + // && lib.version === item.name.substring(item.name.lastIndexOf(':') + 1 + return lib.name === libr.name.substring(0, libr.name.lastIndexOf(':')) && + this.group === libr.group && + libr.status.some(res => res.resource === this.destination.name); + } + ); + }); + this.isDuplicated(this.lib); + }, error => { if (error.status === HTTP_STATUS_CODES.NOT_FOUND || error.status === HTTP_STATUS_CODES.BAD_REQUEST @@ -317,12 +349,23 @@ export class InstallLibrariesComponent implements OnInit, OnDestroy { } }); } else { + this.getMatchedLibs(); + } + } + + private getMatchedLibs() { + if (this.query.length > 1) { this.model.getLibrariesList(this.group, this.query) .subscribe((libs: Library[]) => { - console.log('libs', libs); - console.log(this.query.slice(0, this.query.indexOf(':'))); - this.isLibExist = libs.some(v => v.name === this.query.slice(0, this.query.indexOf(':'))); + this.isLibExist = libs.some(v => v.name === this.query); this.filteredList = libs; + this.filteredList.forEach(lib => { + lib.isInSelectedList = this.model.selectedLibs.some(el => el.name === lib.name); + lib.isInstalled = this.notebookLibs.some(libr => lib.name === libr.name && + this.group === libr.group && + libr.status.some(res => res.resource === this.destination.name)); + }); + this.isDuplicated(this.lib); }); } } @@ -341,7 +384,7 @@ export class InstallLibrariesComponent implements OnInit, OnDestroy { this.isInSelectedList = false; this.uploading = false; this.model.selectedLibs = []; - this.filteredList = null; + this.filteredList = []; this.groupsList = []; clearTimeout(this.clear); @@ -441,54 +484,16 @@ export class ErrorLibMessageDialogComponent { <!-- </mat-list>--> <div class="lib-list" *ngIf="data.type === 'added'"> - <span class="strong">Dependency: </span>{{data.lib.add_pkgs.join(', ')}} + <span class="strong dependency-title">Dependency: </span><span class="packeges" *ngFor="let pack of data.lib.add_pkgs">{{pack+', '}}</span> </div> <div class="lib-list" *ngIf="data.type === 'available'"> -<!-- <p class="terminated">Version is not available</p>--> <span class="strong">Available versions: </span>{{data.lib.available_versions.join(', ')}} </div> -<!-- <div class="text-center">--> -<!-- <button type="button" class="butt" mat-raised-button (click)="dialogRef.close()">Close</button>--> -<!-- </div>--> `, styles: [ ` .lib-list { max-height: 200px; overflow-x: auto; word-break: break-all; padding: 20px 30px !important; margin: 20px 0; color: #577289;} - .terminated{padding-bottom: 15px;} - - .mat-list-base { - padding: 40px 30px; - } - - .object { - width: 70%; - display: flex; - align-items: center; - padding-right: 10px; - } - - .size { - width: 30%; - } - .scrolling-content.delete-list { - max-height: 200px; - overflow-y: auto; - padding-top: 11px; - } - - .empty-list { - display: flex; - width: 100%; - justify-content: center; - color: #35afd5; - padding: 15px; - } - - .list-header { - border-top: 1px solid #edf1f5; - border-bottom: 1px solid #edf1f5; - color: #577289; - width: 100%; - } + .packeges { padding-left: 7px; line-height: 23px;} + .dependency-title{ line-height: 23px; } ` ] }) diff --git a/services/self-service/src/main/resources/webapp/src/styles.scss b/services/self-service/src/main/resources/webapp/src/styles.scss index cc18983..459f495 100644 --- a/services/self-service/src/main/resources/webapp/src/styles.scss +++ b/services/self-service/src/main/resources/webapp/src/styles.scss @@ -140,7 +140,8 @@ mat-chip.mat-chip strong { .terminating, .failed, .deleting, -.deleted { +.deleted, +.invalid_version{ color: #f1696e; } --------------------------------------------------------------------- To unsubscribe, e-mail: commits-unsubscr...@dlab.apache.org For additional commands, e-mail: commits-h...@dlab.apache.org