You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datalab.apache.org by hs...@apache.org on 2022/06/29 12:27:57 UTC
[incubator-datalab] 01/01: [DATALAB-2842] added logic by disable recreate button
This is an automated email from the ASF dual-hosted git repository.
hshpak pushed a commit to branch fix/DATALAB-2842/button-visibility-of-edge-node-recreation
in repository https://gitbox.apache.org/repos/asf/incubator-datalab.git
commit f5e206073610ae80cff54dba8610061828e9e2b6
Author: Hennadii_Shpak <bo...@gmail.com>
AuthorDate: Wed Jun 22 13:46:14 2022 +0300
[DATALAB-2842] added logic by disable recreate button
---
.../create-odahu-cluster.component.ts | 2 +-
.../webapp/src/app/administration/project/index.ts | 8 +-
.../administration/project/project-data.service.ts | 2 +-
.../project/project-form/project-form.component.ts | 8 +-
.../project-list/project-list.component.html | 31 +++--
.../project-list/project-list.component.scss | 19 ++-
.../project/project-list/project-list.component.ts | 141 ++++++++++++---------
.../administration/project/project.component.ts | 29 +----
.../project/project.config.ts} | 16 +--
.../project/project.model.ts} | 29 +++--
.../webapp/src/app/core/directives/index.ts | 8 +-
.../directives/is-endpoint-active.directive.ts | 60 +++++++++
.../core/util/{index.ts => checkEndpointList.ts} | 15 +--
.../webapp/src/app/core/util/checkUtils.ts | 2 +-
.../resources/webapp/src/app/core/util/index.ts | 1 +
.../create-environment.component.ts | 15 ++-
.../resources-grid/resources-grid.component.ts | 2 +-
.../notification-dialog.component.ts | 3 +-
.../src/app/shared/navbar/navbar.component.html | 4 +-
19 files changed, 248 insertions(+), 147 deletions(-)
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/odahu/create-odahu-claster/create-odahu-cluster.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/odahu/create-odahu-claster/create-odahu-cluster.component.ts
index a4f8360fa..e33e2e97e 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/odahu/create-odahu-claster/create-odahu-cluster.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/odahu/create-odahu-claster/create-odahu-cluster.component.ts
@@ -22,11 +22,11 @@ import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { ToastrService } from 'ngx-toastr';
-import { Project } from '../../project/project.component';
import { ProjectService, OdahuDeploymentService } from '../../../core/services';
import { DICTIONARY } from '../../../../dictionary/global.dictionary';
import {CheckUtils, PATTERNS} from '../../../core/util';
+import { Project } from '../../project/project.model';
@Component({
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/index.ts b/services/self-service/src/main/resources/webapp/src/app/administration/project/index.ts
index 8e57f0fb0..d1fd9d7ff 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/project/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/index.ts
@@ -23,15 +23,16 @@ import { FormsModule, ReactiveFormsModule } from '@angular/forms';
import { MaterialModule } from '../../shared/material.module';
import { FormControlsModule } from '../../shared/form-controls';
-import { UnderscorelessPipeModule } from '../../core/pipes/underscoreless-pipe';
import { ProjectFormComponent } from './project-form/project-form.component';
import { ProjectListComponent } from './project-list/project-list.component';
import { ProjectComponent, EditProjectComponent } from './project.component';
import { ProjectDataService } from './project-data.service';
-import {BubbleModule} from "../../shared/bubble";
import {InformMessageModule} from '../../shared/inform-message';
+import { DirectivesModule } from '../../core/directives';
+import { BubbleModule } from '../../shared';
+import { UnderscorelessPipeModule } from '../../core/pipes';
@NgModule({
imports: [
@@ -42,7 +43,8 @@ import {InformMessageModule} from '../../shared/inform-message';
FormControlsModule,
UnderscorelessPipeModule,
BubbleModule,
- InformMessageModule
+ InformMessageModule,
+ DirectivesModule
],
declarations: [ProjectComponent, EditProjectComponent, ProjectFormComponent, ProjectListComponent],
entryComponents: [EditProjectComponent],
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-data.service.ts b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-data.service.ts
index 0cb20d26b..ad9e5c380 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-data.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-data.service.ts
@@ -22,7 +22,7 @@ import { BehaviorSubject, of } from 'rxjs';
import { mergeMap} from 'rxjs/operators';
import { ProjectService, EndpointService } from '../../core/services';
-import { Project } from './project.component';
+import { Project } from './project.model';
@Injectable()
export class ProjectDataService {
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.ts
index b5cd1b84d..d6fe75cde 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-form/project-form.component.ts
@@ -27,9 +27,9 @@ import { Subscription } from 'rxjs';
import { ProjectService, RolesGroupsService, EndpointService, UserAccessKeyService } from '../../../core/services';
import { ProjectDataService } from '../project-data.service';
import { CheckUtils, FileUtils, PATTERNS } from '../../../core/util';
-import { Project } from '../project.component';
import { DICTIONARY } from '../../../../dictionary/global.dictionary';
import {ConfirmationDialogComponent} from '../../../shared/modal-dialog/confirmation-dialog';
+import { Project } from '../project.model';
export interface GenerateKey { privateKey: string; publicKey: string; }
@@ -88,7 +88,7 @@ export class ProjectFormComponent implements OnInit {
() => {
this.toastr.success('Project updated successfully!', 'Success!');
this.update.emit();
- },
+ },
error => this.toastr.error(error.message || 'Project update failed!', 'Oops!')
);
}
@@ -96,7 +96,7 @@ export class ProjectFormComponent implements OnInit {
public confirm(data) {
if (this.item) {
const deletedGroups = this.item.groups.filter((v) => !(this.projectForm.value.groups.includes(v)));
-
+
if (deletedGroups.length) {
this.dialog.open(ConfirmationDialogComponent, {
data: {notebook: deletedGroups, type: 5, manageAction: true}, panelClass: 'modal-md'
@@ -170,7 +170,7 @@ export class ProjectFormComponent implements OnInit {
public selectOptions(list, key, select?) {
- const filter = key === 'endpoints' ? list.filter(el => el.status === 'ACTIVE').map(el => el.name) : list
+ const filter = key === 'endpoints' ? list.filter(el => el.status === 'ACTIVE').map(el => el.name) : list;
this.projectForm.controls[key].setValue(select ? filter : []);
}
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.html
index bf4c8f739..ce81d953a 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.html
@@ -28,7 +28,7 @@
<td mat-cell *matCellDef="let element" class="groups">
<div class="mat-chip-list-wrap scrolling">
<mat-chip-list>
- <mat-chip
+ <mat-chip
*ngFor="let group of element.groups"
[matTooltip]="group"
matTooltipPosition="above"
@@ -45,7 +45,7 @@
<th mat-header-cell *matHeaderCellDef class="endpoints">
<span class="label-endpoint"> Endpoint </span>
<span class="label-endpoint-status"> Endpoint status </span>
- <span class="label-status">Edge node status </span>
+ <span class="label-status">Edge node status</span>
</th>
<td mat-cell *matCellDef="let element" class="source endpoints">
<div *ngIf="!element.endpoints?.length; else list">
@@ -63,9 +63,9 @@
{{ (endpoint.endpointStatus | titlecase) || 'N/A'}}
</span>
</div>
-
+
<span class="status resource-status" [ngClass]="endpoint?.status.toLowerCase() || ''">
- {{ endpoint?.status.toLowerCase() }}
+ {{ endpoint?.status | titlecase }}
</span>
</div>
</ng-template>
@@ -93,11 +93,24 @@
Stop edge node
</a>
</li>
- <li class="project-seting-item " *ngIf="element.areTerminatedNode && isEndpointAvailable" (click)="openEdgeDialog('recreate', element)">
- <i class="material-icons">refresh</i>
- <a class="action">
- Recreate edge node
- </a>
+ <li
+ *ngIf="(element.areTerminatedNode || element.areStoppedNode) && isEndpointAvailable"
+ (click)="openEdgeDialog('recreate', element)"
+
+ >
+ <button class="project-setting-button"
+ #recreateBtn
+ datalabIsEndpointActive
+ [endpointList]="element.endpoints"
+ [matTooltip]="'Unable to recreate edge node if endpoint status is not active.'"
+ matTooltipPosition="above"
+ [matTooltipDisabled]="!isRecreateBtnDisabled(element.endpoints)"
+ >
+ <i class="material-icons">refresh</i>
+ <a class="action" >
+ Recreate edge node
+ </a>
+ </button>
</li>
<li class="project-seting-item " *ngIf="element.areStoppedNode || element.areRunningNode" (click)="openEdgeDialog('terminate', element)">
<i class="material-icons">phonelink_off</i>
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.scss b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.scss
index 836b822f6..0abea7e84 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.scss
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.scss
@@ -138,7 +138,8 @@ td.settings {
}
}
-.project-seting-item {
+.project-seting-item,
+.project-setting-button{
display: flex;
align-items: center;
padding: 10px;
@@ -157,6 +158,18 @@ td.settings {
}
}
+.project-setting-button {
+ width: 100%;
+ background-color: transparent;
+ border: none;
+}
+
+.disabled-button {
+ color: rgba(0,0,0,0.26);
+ background-color: rgba(0,0,0,0.12);
+ cursor: not-allowed;
+}
+
.material-icons {
font-size: 18px;
padding-top: 1px;
@@ -171,11 +184,11 @@ td.settings {
}
.actions-list {
- padding: 10px 15px;
+ padding: 10px 0px;
}
.mat-chip {
max-width: 200px !important;
white-space: nowrap;
display: inline-block;
-}
\ No newline at end of file
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.ts
index ca2c331a4..0086cb918 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project-list/project-list.component.ts
@@ -17,33 +17,37 @@
* under the License.
*/
-import { Component, OnInit, Output, EventEmitter, OnDestroy, Inject, Input } from '@angular/core';
+import { Component, OnInit, Output, EventEmitter, OnDestroy, Inject, Input, ViewChild, ElementRef, AfterViewInit } from '@angular/core';
import { ToastrService } from 'ngx-toastr';
import { MatTableDataSource } from '@angular/material/table';
import { Subscription } from 'rxjs';
import { MatDialogRef, MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog';
import { ProjectDataService } from '../project-data.service';
-import { Project, Endpoint } from '../project.component';
import {ProgressBarService} from '../../../core/services/progress-bar.service';
import {EdgeActionDialogComponent} from '../../../shared/modal-dialog/edge-action-dialog';
import { EndpointService } from '../../../core/services';
+import { Endpoint, ModifiedEndpoint, Project } from '../project.model';
+import { checkEndpointList } from '../../../core/util';
+import { EndpointStatus } from '../project.config';
@Component({
selector: 'project-list',
templateUrl: './project-list.component.html',
styleUrls: ['./project-list.component.scss', '../../../resources/computational/computational-resources-list/computational-resources-list.component.scss']
})
-export class ProjectListComponent implements OnInit, OnDestroy {
+export class ProjectListComponent implements OnInit, OnDestroy, AfterViewInit {
+ @Input() isProjectAdmin: boolean;
+ @Output() editItem: EventEmitter<{}> = new EventEmitter();
+ @Output() toggleStatus: EventEmitter<{}> = new EventEmitter();
+
+ @ViewChild('recreateBtn') recreateBtn: ElementRef;
displayedColumns: string[] = ['name', 'groups', 'endpoints', 'actions'];
dataSource: Project[] | any = [];
projectList: Project[];
isEndpointAvailable: boolean;
- @Input() isProjectAdmin: boolean;
- @Output() editItem: EventEmitter<{}> = new EventEmitter();
- @Output() toggleStatus: EventEmitter<{}> = new EventEmitter();
private subscriptions: Subscription = new Subscription();
constructor (
@@ -56,52 +60,23 @@ export class ProjectListComponent implements OnInit, OnDestroy {
public dialog: MatDialog,
) { }
- ngOnInit() {
+ ngOnInit(): void {
this.getProjectList();
this.getEndpointList();
}
- ngOnDestroy() {
- this.subscriptions.unsubscribe();
- }
+ ngAfterViewInit(): void {
- private getProjectList() {
- this.progressBarService.startProgressBar();
- this.subscriptions.add(this.projectDataService._projects
- .subscribe(
- (value: Project[]) => {
- this.projectList = value;
- if (this.projectList) {
- this.projectList.forEach(project => {
- project.areRunningNode = this.areResoursesInStatuses(project.endpoints, ['RUNNING']);
- project.areStoppedNode = this.areResoursesInStatuses(project.endpoints, ['STOPPED']);
- project.areTerminatedNode = this.areResoursesInStatuses(project.endpoints, ['TERMINATED', 'FAILED']);
- });
- }
- if (value) this.dataSource = new MatTableDataSource(value);
- this.progressBarService.stopProgressBar();
- },
- () => this.progressBarService.stopProgressBar()
- )
- );
}
- private getEndpointList() {
- this.endpointService.getEndpointsData().subscribe(
- (response: Endpoint[] | []) => {
- this.isEndpointAvailable = this.checkIsEndpointAvailable(response);
- }
- )
- }
-
- private checkIsEndpointAvailable(data: Endpoint[] | []): boolean {
- return data.length ? true : false;
+ ngOnDestroy(): void {
+ this.subscriptions.unsubscribe();
}
public showActiveInstances(): void {
const filteredList = this.projectList.map(project => {
project.endpoints = project.endpoints.filter((endpoint: Endpoint) => {
- return endpoint.status !== 'TERMINATED' && endpoint.status !== 'TERMINATING' && endpoint.status !== 'FAILED'
+ return endpoint.status !== 'TERMINATED' && endpoint.status !== 'TERMINATING' && endpoint.status !== 'FAILED';
});
return project;
});
@@ -113,37 +88,83 @@ export class ProjectListComponent implements OnInit, OnDestroy {
this.editItem.emit(item);
}
- public openEdgeDialog(action, project) {
- const endpoints = project.endpoints.filter(endpoint => {
+ public openEdgeDialog(action: string, project: Project) {
+ const endpoints = this.getFilteredEndpointList(action, project);
+
+ if (action === 'terminate' && endpoints.length === 1) {
+ this.toggleStatus.emit({ project, endpoint: endpoints, action, oneEdge: true });
+ } else {
+ this.dialog.open(EdgeActionDialogComponent, { data: { type: action, item: endpoints }, panelClass: 'modal-sm' })
+ .afterClosed().subscribe(
+ endpoint => {
+ if (endpoint && endpoint.length) {
+ this.toggleStatus.emit({project, endpoint, action});
+ }
+ },
+ error => this.toastr.error(error.message || `Endpoint ${action} failed!`, 'Oops!')
+ );
+ }
+ }
+
+ public areResoursesInStatuses(resources, statuses: Array<string>) {
+ return resources.some(resource => statuses.some(status => resource.status === status));
+ }
+
+ isRecreateBtnDisabled(endpointList: ModifiedEndpoint[]): boolean {
+ return checkEndpointList(endpointList);
+ }
+
+ private getFilteredEndpointList(action: string, project) {
+ return project.endpoints.filter(endpoint => {
if (action === 'stop') {
- return endpoint.status === 'RUNNING';
+ return endpoint.status === EndpointStatus.running;
}
if (action === 'start') {
- return endpoint.status === 'STOPPED';
+ return endpoint.status === EndpointStatus.stopped;
}
if (action === 'terminate') {
- return endpoint.status === 'RUNNING' || endpoint.status === 'STOPPED';
+ return endpoint.status === EndpointStatus.running || endpoint.status === EndpointStatus.stopped;
}
if (action === 'recreate') {
- return endpoint.status === 'TERMINATED' || endpoint.status === 'FAILED';
+ return endpoint.status === EndpointStatus.terminated || endpoint.status === EndpointStatus.failed;
}
});
- if (action === 'terminate' && endpoints.length === 1) {
- this.toggleStatus.emit({ project, endpoint: endpoints, action, oneEdge: true });
- } else {
- this.dialog.open(EdgeActionDialogComponent, { data: { type: action, item: endpoints }, panelClass: 'modal-sm' })
- .afterClosed().subscribe(
- endpoint => {
- if (endpoint && endpoint.length) {
- this.toggleStatus.emit({project, endpoint, action});
- }
- },
- error => this.toastr.error(error.message || `Endpoint ${action} failed!`, 'Oops!')
- );
+ }
+
+ private getProjectList() {
+ this.progressBarService.startProgressBar();
+ this.subscriptions.add(this.projectDataService._projects
+ .subscribe(
+ (value: Project[]) => {
+ this.modifyProjectList(value);
+ if (value) this.dataSource = new MatTableDataSource(value);
+ this.progressBarService.stopProgressBar();
+ },
+ () => this.progressBarService.stopProgressBar()
+ )
+ );
+ }
+
+ private modifyProjectList(value: Project[]): void {
+ this.projectList = value;
+ if (this.projectList) {
+ this.projectList.forEach(project => {
+ project.areRunningNode = this.areResoursesInStatuses(project.endpoints, [EndpointStatus.running]);
+ project.areStoppedNode = this.areResoursesInStatuses(project.endpoints, [EndpointStatus.stopped]);
+ project.areTerminatedNode = this.areResoursesInStatuses(project.endpoints, [EndpointStatus.terminated, EndpointStatus.failed]);
+ });
}
}
- public areResoursesInStatuses(resources, statuses: Array<string>) {
- return resources.some(resource => statuses.some(status => resource.status === status));
+ private getEndpointList() {
+ this.endpointService.getEndpointsData().subscribe(
+ (response: Endpoint[] | []) => {
+ this.isEndpointAvailable = this.checkIsEndpointAvailable(response);
+ }
+ );
+ }
+
+ private checkIsEndpointAvailable(data: Endpoint[] | []): boolean {
+ return data.length ? true : false;
}
}
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.ts
index 1409c7b80..61e486590 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project.component.ts
@@ -27,23 +27,8 @@ import {HealthStatusService, ProjectService } from '../../core/services';
import { NotificationDialogComponent } from '../../shared/modal-dialog/notification-dialog';
import { ProjectListComponent } from './project-list/project-list.component';
import { EnvironmentsDataService } from '../management/management-data.service';
+import { Project } from './project.model';
-export interface Endpoint {
- name: string;
- status: string;
- edgeInfo: any;
-}
-
-export interface Project {
- name: string;
- endpoints: any;
- tag: string;
- groups: string[];
- shared_image_enabled?: boolean;
- areStoppedNode?: boolean;
- areTerminatedNode?: boolean;
- areRunningNode?: boolean;
-}
@Component({
selector: 'datalab-project',
@@ -118,8 +103,8 @@ export class ProjectComponent implements OnInit, OnDestroy {
}
public toggleStatus($event) {
- const data = {
- 'project_name': $event.project.name,
+ const data = {
+ 'project_name': $event.project.name,
endpoint: $event.endpoint.map(endpoint => endpoint.name),
'edge_status': $event.endpoint.map(endpoint => endpoint.status)[0]
};
@@ -129,11 +114,11 @@ export class ProjectComponent implements OnInit, OnDestroy {
private toggleStatusRequest(data, action, isOnlyOneEdge?) {
if ( action === 'terminate') {
const projectsResources = this.resources
- .filter(resource => resource.project === data.project_name && resource.resource_type !== "edge node");
+ .filter(resource => resource.project === data.project_name && resource.resource_type !== 'edge node');
const activeProjectsResources = projectsResources?.length ? projectsResources
.filter(expl => expl.status !== 'terminated' && expl.status !== 'terminating' && expl.status !== 'failed') : [];
-
+
const termResources = data.endpoint.reduce((res, endp) => {
res.push(...activeProjectsResources.filter(resource => resource.endpoint === endp));
return res;
@@ -143,7 +128,7 @@ export class ProjectComponent implements OnInit, OnDestroy {
this.edgeNodeAction(data, action);
} else {
this.dialog.open(NotificationDialogComponent, { data: {
- type: 'terminateNode',
+ type: 'terminateNode',
item: {action: data, resources: termResources}
}, panelClass: 'modal-sm' })
.afterClosed().subscribe(result => {
@@ -161,7 +146,7 @@ export class ProjectComponent implements OnInit, OnDestroy {
() => {
this.refreshGrid();
this.toastr.success(`Edge node ${this.toEndpointAction(action)} is in progress!`, 'Processing!');
- },
+ },
error => {
this.toastr.error(error.message, 'Oops!');
}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/util/index.ts b/services/self-service/src/main/resources/webapp/src/app/administration/project/project.config.ts
similarity index 74%
copy from services/self-service/src/main/resources/webapp/src/app/core/util/index.ts
copy to services/self-service/src/main/resources/webapp/src/app/administration/project/project.config.ts
index 8c04f80aa..fa333d082 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/util/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project.config.ts
@@ -17,12 +17,10 @@
* under the License.
*/
-export * from './http-status-codes';
-export * from './sortUtils';
-export * from './helpUtils';
-export * from './errorUtils';
-export * from './dateUtils';
-export * from './fileUtils';
-export * from './checkUtils';
-export * from './patterns';
-export * from './http-methods';
+export enum EndpointStatus {
+ terminated = 'TERMINATED',
+ terminating = 'TERMINATING',
+ failed = 'FAILED',
+ running = 'RUNNING',
+ stopped = 'STOPPED',
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/util/index.ts b/services/self-service/src/main/resources/webapp/src/app/administration/project/project.model.ts
similarity index 66%
copy from services/self-service/src/main/resources/webapp/src/app/core/util/index.ts
copy to services/self-service/src/main/resources/webapp/src/app/administration/project/project.model.ts
index 8c04f80aa..bfdc79030 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/util/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/project/project.model.ts
@@ -17,12 +17,23 @@
* under the License.
*/
-export * from './http-status-codes';
-export * from './sortUtils';
-export * from './helpUtils';
-export * from './errorUtils';
-export * from './dateUtils';
-export * from './fileUtils';
-export * from './checkUtils';
-export * from './patterns';
-export * from './http-methods';
+export interface Endpoint {
+ name: string;
+ status: string;
+ edgeInfo: any;
+}
+
+export interface ModifiedEndpoint extends Endpoint {
+ endpointStatus?: 'ACTIVE' | 'INACTIVE';
+}
+
+export interface Project {
+ name: string;
+ endpoints: any;
+ tag: string;
+ groups: string[];
+ shared_image_enabled?: boolean;
+ areStoppedNode?: boolean;
+ areTerminatedNode?: boolean;
+ areRunningNode?: boolean;
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/directives/index.ts b/services/self-service/src/main/resources/webapp/src/app/core/directives/index.ts
index 83a0eaee4..9f8dcb2b2 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/directives/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/directives/index.ts
@@ -22,14 +22,12 @@ import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ClickOutsideDirective } from './click-outside.directive';
import { ScrollDirective } from './scrollTo.directive';
-
-export * from './scrollTo.directive';
-export * from './click-outside.directive';
+import { IsEndpointsActiveDirective } from './is-endpoint-active.directive';
@NgModule({
imports: [CommonModule],
- declarations: [ClickOutsideDirective, ScrollDirective],
- exports: [ClickOutsideDirective, ScrollDirective]
+ declarations: [ClickOutsideDirective, ScrollDirective, IsEndpointsActiveDirective],
+ exports: [ClickOutsideDirective, ScrollDirective, IsEndpointsActiveDirective]
})
export class DirectivesModule { }
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/directives/is-endpoint-active.directive.ts b/services/self-service/src/main/resources/webapp/src/app/core/directives/is-endpoint-active.directive.ts
new file mode 100644
index 000000000..0f9db68bd
--- /dev/null
+++ b/services/self-service/src/main/resources/webapp/src/app/core/directives/is-endpoint-active.directive.ts
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import { Directive, ElementRef, HostListener, Input, OnInit, Renderer2 } from '@angular/core';
+
+import { ModifiedEndpoint } from '../../administration/project/project.model';
+import { checkEndpointList } from '../util';
+
+
+@Directive({
+ selector: '[datalabIsEndpointActive]'
+})
+export class IsEndpointsActiveDirective implements OnInit {
+ @Input() endpointList: ModifiedEndpoint[];
+
+ private isButtonDisabled: boolean = false;
+
+ constructor (
+ private el: ElementRef,
+ private renderer: Renderer2
+ ) { }
+
+ ngOnInit(): void {
+ this.checkEndpointList(this.endpointList);
+ this.setStyle();
+ }
+
+ @HostListener('click', ['$event'])
+ onClick(event: Event): void {
+ if (this.isButtonDisabled) {
+ event.stopPropagation();
+ }
+ }
+
+ private setStyle() {
+ if (this.isButtonDisabled) {
+ this.renderer.addClass(this.el.nativeElement, 'disabled-button');
+ }
+ }
+
+ private checkEndpointList(endpointList: ModifiedEndpoint[]): void {
+ this.isButtonDisabled = checkEndpointList(endpointList);
+ }
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/util/index.ts b/services/self-service/src/main/resources/webapp/src/app/core/util/checkEndpointList.ts
similarity index 72%
copy from services/self-service/src/main/resources/webapp/src/app/core/util/index.ts
copy to services/self-service/src/main/resources/webapp/src/app/core/util/checkEndpointList.ts
index 8c04f80aa..99f927ddc 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/util/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/util/checkEndpointList.ts
@@ -17,12 +17,9 @@
* under the License.
*/
-export * from './http-status-codes';
-export * from './sortUtils';
-export * from './helpUtils';
-export * from './errorUtils';
-export * from './dateUtils';
-export * from './fileUtils';
-export * from './checkUtils';
-export * from './patterns';
-export * from './http-methods';
+import { ModifiedEndpoint } from '../../administration/project/project.model';
+
+export const checkEndpointList = (endpointList: ModifiedEndpoint[]): boolean => {
+ return endpointList.every(({status, endpointStatus}) => (status === 'TERMINATED' || status === 'FAILED')
+ && endpointStatus === 'INACTIVE');
+};
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/util/checkUtils.ts b/services/self-service/src/main/resources/webapp/src/app/core/util/checkUtils.ts
index d1e6f535e..ca3e5a2c2 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/util/checkUtils.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/util/checkUtils.ts
@@ -28,7 +28,7 @@ export class CheckUtils {
STOPPING: 'DISCONNECTING',
STOPPED: 'DISCONNECTED'
};
-
+
public static isJSON(str) {
try {
JSON.parse(str);
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/util/index.ts b/services/self-service/src/main/resources/webapp/src/app/core/util/index.ts
index 8c04f80aa..b00239022 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/util/index.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/util/index.ts
@@ -26,3 +26,4 @@ export * from './fileUtils';
export * from './checkUtils';
export * from './patterns';
export * from './http-methods';
+export * from './checkEndpointList';
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.ts
index d0b107ea5..debc6515c 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/create-environment/create-environment.component.ts
@@ -22,7 +22,6 @@ import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { ToastrService } from 'ngx-toastr';
-import { Project } from '../../../administration/project/project.component';
import { UserResourceService, ProjectService } from '../../../core/services';
import { CheckUtils, SortUtils, HTTP_STATUS_CODES, PATTERNS, HelpUtils } from '../../../core/util';
import { DICTIONARY } from '../../../../dictionary/global.dictionary';
@@ -30,6 +29,7 @@ import { CLUSTER_CONFIGURATION } from '../../computational/computational-resourc
import { tap } from 'rxjs/operators';
import { timer } from 'rxjs';
import { TemplateName } from '../../../core/models';
+import { Project } from '../../../administration/project/project.model';
@Component({
selector: 'create-environment',
@@ -181,7 +181,8 @@ export class ExploratoryEnvironmentCreateComponent implements OnInit {
this.gpuTypes = template?.computationGPU ? HelpUtils.sortGpuTypes(template.computationGPU) : [];
- if(template?.image === 'docker.datalab-tensor' /**|| template?.image === 'docker.datalab-jupyter-conda'|| template?.image === 'docker.datalab-jupyter-gpu' */|| template?.image === 'docker.datalab-deeplearning') {
+ // tslint:disable-next-line:max-line-length
+ if (template?.image === 'docker.datalab-tensor' /**|| template?.image === 'docker.datalab-jupyter-conda'|| template?.image === 'docker.datalab-jupyter-gpu' */|| template?.image === 'docker.datalab-deeplearning') {
this.addGpuFields();
}
}
@@ -272,9 +273,9 @@ export class ExploratoryEnvironmentCreateComponent implements OnInit {
}
public setInstanceSize() {
- const {image, computationGPU} = this.currentTemplate
- if(image === this.templateName.jupyterJpu) {
- this.createExploratoryForm.get('gpu_count').setValue(computationGPU[0])
+ const {image, computationGPU} = this.currentTemplate;
+ if (image === this.templateName.jupyterJpu) {
+ this.createExploratoryForm.get('gpu_count').setValue(computationGPU[0]);
} else {
const controls = ['gpu_type', 'gpu_count'];
controls.forEach(control => {
@@ -329,9 +330,9 @@ export class ExploratoryEnvironmentCreateComponent implements OnInit {
(res: any) => {
this.images = res.filter(el => el.status === 'CREATED');
- if(this.selectedCloud === 'gcp' && this.currentTemplate.image === 'docker.datalab-deeplearning') {
+ if (this.selectedCloud === 'gcp' && this.currentTemplate.image === 'docker.datalab-deeplearning') {
this.currentTemplate.exploratory_environment_images = this.currentTemplate.exploratory_environment_images.map(image => {
- return {name: image['Image family'] ?? image.name, description: image['Description'] ?? image.description}
+ return {name: image['Image family'] ?? image.name, description: image['Description'] ?? image.description};
});
this.images.push(...this.currentTemplate.exploratory_environment_images);
}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.ts
index 28b79ecd8..4677f57d2 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/resources-grid/resources-grid.component.ts
@@ -17,7 +17,6 @@
* under the License.
*/
-import { Project } from '../../administration/project/project.component';
import {
Component,
EventEmitter,
@@ -47,6 +46,7 @@ import { NotebookModel } from '../exploratory/notebook.model';
import { AuditService } from '../../core/services/audit.service';
import { CompareUtils } from '../../core/util/compareUtils';
import { OdahuActionDialogComponent } from '../../shared/modal-dialog/odahu-action-dialog';
+import { Project } from '../../administration/project/project.model';
export interface SharedEndpoint {
edge_node_ip: string;
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/notification-dialog/notification-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/notification-dialog/notification-dialog.component.ts
index 2cdee43fc..4f532c0e8 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/notification-dialog/notification-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/modal-dialog/notification-dialog/notification-dialog.component.ts
@@ -19,7 +19,8 @@
import { Component, Inject } from '@angular/core';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
-import {Endpoint} from '../../../administration/project/project.component';
+
+import { Endpoint } from '../../../administration/project/project.model';
@Component({
selector: 'notification-dialog',
diff --git a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html
index 4ec0819a6..8ae321ffe 100644
--- a/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/shared/navbar/navbar.component.html
@@ -28,8 +28,8 @@
<span class="line"></span>
</button>
- <a [routerLink]="['/resources_list']" class="navbar-logo">
- <img src="assets/svg/logo.svg" alt="">
+ <a [routerLink]="['/instances']" class="navbar-logo">
+ <img src="assets/svg/logo.svg" alt="datalab">
</a>
</div>
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datalab.apache.org
For additional commands, e-mail: commits-help@datalab.apache.org