You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@datalab.apache.org by dy...@apache.org on 2022/05/18 10:35:39 UTC
[incubator-datalab] branch DATALAB-2785 updated (407d81834 -> 36be6ec70)
This is an automated email from the ASF dual-hosted git repository.
dyankiv pushed a change to branch DATALAB-2785
in repository https://gitbox.apache.org/repos/asf/incubator-datalab.git
from 407d81834 fix params for create image
add c820988cc applied nbformat 5.3.0 version during jupyter installation
add 39b448e1d Merge pull request #1515 from apache/DATALAB-2795
add a7cbe5ad8 added possibility to add several users
add 479914874 Merge pull request #1516 from apache/fix/DATALAB-2800/possibility-to-add-several-users
add de1f23fa2 name correction
add dbaea5d9f Merge pull request #1517 from apache/DATALAB-2783
add 056abd7e2 [DATALAB-2768]: added connection restart to python server
add 80e8ea9dc [DATALAB-2768]: changed retrying cycle concept
add 13c84a9fc Merge pull request #1514 from a1expol/develop
add de6b274f5 [DATALAB-2768]: fixed issue with 'other' group libs
add 241cc6f57 [DATALAB-2768]: fixed issue with 'other' group libs
add 94a159411 Merge pull request #1518 from a1expol/develop
new acf9d94e8 added create ami button
new ac1a9a61d Merge remote-tracking branch 'origin/feat/DATALAB-2771/add-create-image-btn-for-admin' into DATALAB-2785
new a29aa0622 [DATALAB-2771] created create image btn
new e6a9f09a4 resolve conflict
add a9dd17edf fixed for all clouds
add 2d606a001 Merge pull request #1519 from apache/DATALAB-2795
add c4fa92fcf [DATALAB-2793]: removed broken cuda repo from azure deeplearning
add 0fa8e198b Merge pull request #1521 from apache/DATALAB-2793
new ae8007f5d [DATALAB-2771] created create image btn
new 01496306b resolve conflict
new 3f9df815d [DATALAB-2771] created create image btn
new 9b44f4238 Merge remote-tracking branch 'origin/feat/DATALAB-2771/add-create-image-btn-for-admin' into DATALAB-2785
new 36be6ec70 small fix
The 9 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails. The revisions
listed as "add" were already present in the repository and have only
been added to this reference.
Summary of changes:
.../src/general/conf/datalab.ini | 2 +
.../files/aws/tensor-jupyterlab_description.json | 4 +-
.../src/general/lib/os/debian/notebook_lib.py | 16 +-
.../src/general/lib/os/fab.py | 3 +
.../general/scripts/os/get_list_available_pkgs.py | 56 ++++--
.../src/ssn/files/aws/mongo_roles.json | 2 +-
.../backendapi/domain/NotebookTemplate.java | 2 +-
.../backendapi/resources/EnvironmentResource.java | 15 +-
.../dto/ExploratoryImageCreateFormAdminDTO.java | 23 +++
.../service/impl/EnvironmentServiceImpl.java | 6 +-
.../src/main/resources/mongo/aws/mongo_roles.json | 2 +-
.../management-grid/management-grid.component.html | 221 +++++++++++----------
.../management-grid/management-grid.component.ts | 47 +++--
.../management/management.component.ts | 19 +-
.../administration/management/management.model.ts | 13 +-
.../app/administration/roles/roles.component.ts | 41 ++--
.../convert-action-type.pipe.ts | 28 +--
.../services/applicationServiceFacade.service.ts | 4 +-
.../ami-create-dialog.component.html | 16 +-
.../ami-create-dialog.component.ts | 32 ++-
20 files changed, 330 insertions(+), 222 deletions(-)
create mode 100644 services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryImageCreateFormAdminDTO.java
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datalab.apache.org
For additional commands, e-mail: commits-help@datalab.apache.org
[incubator-datalab] 02/09: Merge remote-tracking branch 'origin/feat/DATALAB-2771/add-create-image-btn-for-admin' into DATALAB-2785
Posted by dy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
dyankiv pushed a commit to branch DATALAB-2785
in repository https://gitbox.apache.org/repos/asf/incubator-datalab.git
commit ac1a9a61d5dad40300ac57d8cf3b9568cee57496
Merge: 407d81834 acf9d94e8
Author: Denys Yankiv <de...@gmail.com>
AuthorDate: Thu May 12 12:58:49 2022 +0300
Merge remote-tracking branch 'origin/feat/DATALAB-2771/add-create-image-btn-for-admin' into DATALAB-2785
.../src/general/conf/datalab.ini | 2 +
.../files/aws/tensor-jupyterlab_description.json | 4 +-
.../src/general/lib/os/debian/notebook_lib.py | 8 +-
.../general/scripts/os/get_list_available_pkgs.py | 56 ++++--
.../src/ssn/files/aws/mongo_roles.json | 2 +-
.../backendapi/domain/NotebookTemplate.java | 2 +-
.../src/main/resources/mongo/aws/mongo_roles.json | 2 +-
.../management-grid/management-grid.component.html | 221 +++++++++++----------
.../management-grid/management-grid.component.ts | 42 ++--
.../management/management.component.ts | 19 +-
.../administration/management/management.model.ts | 13 +-
.../app/administration/roles/roles.component.ts | 41 ++--
.../ami-create-dialog.component.html | 16 +-
.../ami-create-dialog.component.ts | 32 ++-
14 files changed, 268 insertions(+), 192 deletions(-)
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datalab.apache.org
For additional commands, e-mail: commits-help@datalab.apache.org
[incubator-datalab] 06/09: [DATALAB-2771] created create image btn
Posted by dy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
dyankiv pushed a commit to branch DATALAB-2785
in repository https://gitbox.apache.org/repos/asf/incubator-datalab.git
commit 3f9df815d76d4b2eacee215d44b8ef0c529d080f
Author: Hennadii_Shpak <bo...@gmail.com>
AuthorDate: Tue May 3 18:18:27 2022 +0300
[DATALAB-2771] created create image btn
---
.../management-grid/management-grid.component.html | 221 +++++++++++----------
.../management-grid/management-grid.component.ts | 47 +++--
.../management/management.component.ts | 19 +-
.../administration/management/management.model.ts | 13 +-
.../convert-action-type.pipe.ts | 28 +--
.../services/applicationServiceFacade.service.ts | 4 +-
.../ami-create-dialog.component.html | 16 +-
.../ami-create-dialog.component.ts | 32 ++-
8 files changed, 215 insertions(+), 165 deletions(-)
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
index c8c793d8c..43c7534ee 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
@@ -18,14 +18,14 @@
-->
<div class="managment-wrapper scrolling" #pageWrapper (scroll)="scrollTable($event)" (resize)="onResize($event)">
<div class="ani scrolling scroll-wrapper" #wrapper (scroll)="scrollTable($event)">
- <div
- class="nav-buttons"
+ <div
+ class="nav-buttons"
[ngStyle]="{'width.px': userAgentIndex === -1 ? tableWrapperWidth - 3 : tableWrapperWidth - 7 }"
- [ngClass]="{'border': tableEl['offsetHeight'] < tableWrapper.offsetHeight - 48}"
+ [ngClass]="{'border': tableEl['offsetHeight'] < tableWrapper.offsetHeight - 48}"
[hidden]="!(tableWrapper.offsetWidth - tableEl['offsetWidth'] < 0)"
>
<div class="button-container">
- <button
+ <button
mat-mini-fab aria-label="Scroll left"
(click)="sctollTo('left')"
[ngClass]="{'not-allowed': wrapper.scrollLeft === 0 }"
@@ -34,7 +34,7 @@
</button>
</div>
<div class="button-container" [ngClass]="{'not-allowed': checkMaxRight()}">
- <button
+ <button
mat-mini-fab aria-label="Scroll right"
(click)="sctollTo('right')"
[ngClass]="{'not-allowed': !(isMaxRight | async)}"
@@ -61,10 +61,10 @@
</button>
</th>
<td mat-cell *matCellDef="let element">
- <ng-template
- [ngIf]="element.type !== 'odahu'
- && element.type !== 'edge node'
- && (element.status==='running' || element.status==='stopped')
+ <ng-template
+ [ngIf]="element.type !== 'odahu'
+ && element.type !== 'edge node'
+ && (element.status==='running' || element.status==='stopped')
&& !clustersInProgress(element.resources)"
>
<datalab-checkbox
@@ -79,10 +79,10 @@
<ng-container matColumnDef="user">
<th mat-header-cell *matHeaderCellDef class="user label-header">
<span class="label">User</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -105,17 +105,17 @@
<ng-container matColumnDef="project">
<th mat-header-cell *matHeaderCellDef class="project label-header">
<span class="label">Project</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
<span *ngIf="filtering && filterForm.projects.length > 0 && !collapsedFilterRow">filter_list</span>
<span [hidden]="filtering && filterForm.projects.length > 0 && !collapsedFilterRow">more_vert</span>
</i>
- </button>
+ </button>
</th>
<td mat-cell *matCellDef="let element">{{ element.project }}</td>
</ng-container>
@@ -123,10 +123,10 @@
<ng-container matColumnDef="endpoint">
<th mat-header-cell *matHeaderCellDef class="endpoint label-header">
<span class="label">Endpoint</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -141,10 +141,10 @@
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef class="type label-header">
<span class="label">Name</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -168,10 +168,10 @@
<ng-container matColumnDef="shape">
<th mat-header-cell *matHeaderCellDef class="shape label-header">
<span class="label">Shape / Resource id</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -190,10 +190,10 @@
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef class="status label-header">
<span class="label">Status</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -210,10 +210,10 @@
<ng-container matColumnDef="resources">
<th mat-header-cell *matHeaderCellDef class="resources label-header">
<span class="label">Compute</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -236,8 +236,8 @@
<div class="resource-actions">
<span class="not-allow">
<a class="start-stop-action" *ngIf="resource.image === 'docker.datalab-dataengine'">
- <i
- class="material-icons"
+ <i
+ class="material-icons"
(click)="toggleResourceAction(element, 'stop', resource)"
[ngClass]="{'not-allowed' : resource.status !== 'running' || selected?.length }"
>
@@ -246,8 +246,8 @@
</a>
</span>
<span class="not-allow">
- <a
- class="remove_butt"
+ <a
+ class="remove_butt"
(click)="toggleResourceAction(element, 'terminate', resource)"
[ngClass]="{ 'disabled' : element.status !== 'running' || (resource.status !== 'running' && resource.status !== 'stopped') || selected?.length }"
>
@@ -267,10 +267,10 @@
</th>
<td mat-cell *matCellDef="let element" class="settings actions-col">
<span [ngClass]="{'not-allow' : selected?.length}">
- <span
- #settings
- class="actions"
- (click)="actions.toggle($event, settings)"
+ <span
+ #settings
+ class="actions"
+ (click)="actions.toggle($event, settings)"
*ngIf="element.type !== 'edge node' && element.type !== 'odahu'"
[ngClass]="{
'disabled' : (element.status !== 'running' && element.status !== 'stopped')
@@ -281,39 +281,50 @@
<bubble-up #actions class="list-menu" position="bottom-left" alternative="top-left">
<ul class="list-unstyled">
<li
- matTooltip="{{ element.type !== 'edge node'
- ? 'Unable to stop notebook because at least one computational resource is in progress'
+ matTooltip="{{ element.type !== 'edge node'
+ ? 'Unable to stop notebook because at least one computational resource is in progress'
: 'Unable to stop edge node because at least one resource of this user is in progress' }}"
- matTooltipPosition="above"
+ matTooltipPosition="above"
[matTooltipDisabled]="!isResourcesInProgress(element)"
[hidden]="element.name === 'edge node' && element.status === 'stopped'"
>
- <div
+ <div
(click)="toggleResourceAction(element, 'stop')"
- [ngClass]="{'not-allowed' : element.status === 'stopped' || element.status === 'stopping' ||
- element.status === 'starting' || element.status === 'creating image' ||
+ [ngClass]="{'not-allowed' : element.status === 'stopped' || element.status === 'stopping' ||
+ element.status === 'starting' || element.status === 'creating image' ||
element.status === 'failed' || isResourcesInProgress(element)}"
>
<i class="material-icons">pause_circle_outline</i>
<span>Stop</span>
</div>
</li>
- <li
+ <li
*ngIf="element.name !== 'edge node'"
matTooltip="Unable to terminate notebook because at least one compute is in progress"
- matTooltipPosition="above"
+ matTooltipPosition="above"
[matTooltipDisabled]="!isResourcesInProgress(element)"
>
- <div
+ <div
(click)="toggleResourceAction(element, 'terminate')"
- [ngClass]="{'not-allowed' : element.status !== 'running' &&
- element.status !== 'stopped' ||
+ [ngClass]="{'not-allowed' : element.status !== 'running' &&
+ element.status !== 'stopped' ||
isResourcesInProgress(element)}"
>
<i class="material-icons">phonelink_off</i>
<span>Terminate</span>
</div>
</li>
+ <li
+ *ngIf="element.status !== 'terminated' && element.image !== 'docker.datalab-superset'
+ && element.image !== 'docker.datalab-jupyterlab'"
+ >
+ <div
+ (click)="toggleResourceAction(element, 'create image')"
+ >
+ <i class="material-icons">view_module</i>
+ <span>Create Image</span>
+ </div>
+ </li>
<li *ngIf="element.status === 'stopped'">
<div (click)="toggleResourceAction(element, 'start')">
<i class="material-icons">play_circle_outline</i>
@@ -333,9 +344,9 @@
<ng-container matColumnDef="user-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
- [type]="'users'"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
+ [type]="'users'"
[items]="filterConfiguration.users"
[model]="filterForm.users"
></multi-select-dropdown>
@@ -344,11 +355,11 @@
<ng-container matColumnDef="type-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <input
- placeholder="Filter by name"
- type="text"
+ <input
+ placeholder="Filter by name"
+ type="text"
class="form-control filter-field"
- [value]="filterForm.type"
+ [value]="filterForm.type"
(input)="onFilterNameUpdate($event.target['value'])"
/>
</th>
@@ -356,20 +367,20 @@
<ng-container matColumnDef="project-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'projects'"
- [items]="filterConfiguration.projects"
+ [items]="filterConfiguration.projects"
[model]="filterForm.projects"
></multi-select-dropdown>
</th>
</ng-container>
<ng-container matColumnDef="endpoint-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'endpoints'"
- [items]="filterConfiguration.endpoints"
+ [items]="filterConfiguration.endpoints"
[model]="filterForm.endpoints"
></multi-select-dropdown>
</th>
@@ -377,10 +388,10 @@
<ng-container matColumnDef="shape-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'shapes'"
- [items]="filterConfiguration.shapes"
+ [items]="filterConfiguration.shapes"
[model]="filterForm.shapes"
></multi-select-dropdown>
</th>
@@ -388,10 +399,10 @@
<ng-container matColumnDef="status-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'statuses'"
- [items]="filterConfiguration.statuses"
+ [items]="filterConfiguration.statuses"
[model]="filterForm.statuses"
></multi-select-dropdown>
</th>
@@ -399,10 +410,10 @@
<ng-container matColumnDef="resource-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'resources'"
- [items]="filterConfiguration.resources"
+ [items]="filterConfiguration.resources"
[model]="filterForm.resources"
></multi-select-dropdown>
</th>
@@ -411,22 +422,22 @@
<ng-container matColumnDef="actions-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="actions-col filter-row-item">
<div class="actions">
- <button
- mat-icon-button
- class="btn reset"
- (click)="resetFilterConfigurations()"
+ <button
+ mat-icon-button
+ class="btn reset"
+ (click)="resetFilterConfigurations()"
[disabled]="!isFilterSelected"
>
<i class="material-icons">close</i>
</button>
- <button
- mat-icon-button
- class="btn apply"
+ <button
+ mat-icon-button
+ class="btn apply"
(click)="applyFilter(filterForm)"
[disabled]="isFilterChanged"
>
- <i
+ <i
class="material-icons"
[ngClass]="{'not-allowed': allFilteredEnvironmentData?.length == 0 && !filtering}"
>
@@ -439,7 +450,7 @@
<ng-container matColumnDef="placeholder">
<td mat-footer-cell *matFooterCellDef colspan="8" class="no-border">
- <div
+ <div
class="info"
*ngIf="(!allFilteredEnvironmentData) && !filtering || (allFilteredEnvironmentData?.length == 0) && !filtering"
>
@@ -450,36 +461,36 @@
</ng-container>
<ng-container matColumnDef="scrollButtons">
- <td
- mat-footer-cell
- *matFooterCellDef
- colspan="9"
+ <td
+ mat-footer-cell
+ *matFooterCellDef
+ colspan="9"
class="buttons-wrap"
></td>
</ng-container>
- <tr
- mat-header-row
- *matHeaderRowDef="displayedColumns; sticky: true"
+ <tr
+ mat-header-row
+ *matHeaderRowDef="displayedColumns; sticky: true"
class="header-row"
></tr>
- <tr
- [hidden]="!collapsedFilterRow"
- mat-header-row
+ <tr
+ [hidden]="!collapsedFilterRow"
+ mat-header-row
*matHeaderRowDef="displayedFilterColumns; sticky: true"
class="filter-row"
></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
- <tr
- [hidden]="allFilteredEnvironmentData?.length"
- mat-footer-row *matFooterRowDef="['placeholder']"
+ <tr
+ [hidden]="allFilteredEnvironmentData?.length"
+ mat-footer-row *matFooterRowDef="['placeholder']"
class="info"
></tr>
- <tr
- [hidden]="!tableEl || !tableEl['offsetWidth'] || tableWrapper.offsetWidth - tableEl['offsetWidth'] > -16 || !allFilteredEnvironmentData?.length"
- mat-footer-row
- *matFooterRowDef="['scrollButtons']; sticky: true"
+ <tr
+ [hidden]="!tableEl || !tableEl['offsetWidth'] || tableWrapper.offsetWidth - tableEl['offsetWidth'] > -16 || !allFilteredEnvironmentData?.length"
+ mat-footer-row
+ *matFooterRowDef="['scrollButtons']; sticky: true"
class="info"
></tr>
</table>
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
index a122af1c6..d757eedac 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
@@ -142,7 +142,7 @@ export class ManagementGridComponent implements OnInit, AfterViewInit, AfterView
this.applyFilter(this.cashedFilterForm || this.filterForm);
}
this.progressBarService.stopProgressBar();
- },
+ },
() => {
this.progressBarService.stopProgressBar();
}
@@ -186,8 +186,8 @@ export class ManagementGridComponent implements OnInit, AfterViewInit, AfterView
const containsStatus = (list, selectedItems) => {
if (list) {
- return list.filter((item: any) => {
- if (selectedItems.indexOf(item.status) !== -1) return item;
+ return list.filter((item: any) => {
+ if (selectedItems.indexOf(item.status) !== -1) return item;
});
}
};
@@ -196,30 +196,30 @@ export class ManagementGridComponent implements OnInit, AfterViewInit, AfterView
if (config) {
filteredData = filteredData.filter(item => {
const isUser = config.users.length > 0 ? (config.users.indexOf(item.user) !== -1) : true;
- const isTypeName = item.name
- ? item.name.toLowerCase().indexOf(config.type.toLowerCase()) !== -1
+ const isTypeName = item.name
+ ? item.name.toLowerCase().indexOf(config.type.toLowerCase()) !== -1
: item.type.toLowerCase().indexOf(config.type.toLowerCase()) !== -1;
- const isStatus = config.statuses.length > 0
- ? (config.statuses.indexOf(item.status) !== -1)
+ const isStatus = config.statuses.length > 0
+ ? (config.statuses.indexOf(item.status) !== -1)
: (config.type !== 'active');
- const isShape = config.shapes.length > 0
+ const isShape = config.shapes.length > 0
? (config.shapes.indexOf(item.shape) !== -1 ||
config.shapes.indexOf(item.gpu_type) !== -1 ||
- config.shapes.indexOf(`GPU count: ${item.gpu_count}`) !== -1)
+ config.shapes.indexOf(`GPU count: ${item.gpu_count}`) !== -1)
: true;
- const isProject = config.projects.length > 0
- ? (config.projects.indexOf(item.project) !== -1)
+ const isProject = config.projects.length > 0
+ ? (config.projects.indexOf(item.project) !== -1)
: true;
- const isEndpoint = config.endpoints.length > 0
- ? (config.endpoints.indexOf(item.endpoint) !== -1)
+ const isEndpoint = config.endpoints.length > 0
+ ? (config.endpoints.indexOf(item.endpoint) !== -1)
: true;
const modifiedResources = containsStatus(item.resources, config.resources);
- let isResources = config.resources.length > 0
- ? (modifiedResources && modifiedResources.length > 0)
+ let isResources = config.resources.length > 0
+ ? (modifiedResources && modifiedResources.length > 0)
: true;
- if (config.resources.length > 0 && modifiedResources && modifiedResources.length > 0) {
- item.resources = modifiedResources;
+ if (config.resources.length > 0 && modifiedResources && modifiedResources.length > 0) {
+ item.resources = modifiedResources;
}
if (config.resources && config.resources.length === 0 && config.type === 'active' ||
@@ -288,7 +288,13 @@ export class ManagementGridComponent implements OnInit, AfterViewInit, AfterView
}
});
- this.filterConfiguration = new ManagementConfigModel(users, '', projects, [...shapes, ...gpuTypes, ...gpuCounts], statuses, resources, endpoints);
+ this.filterConfiguration = new ManagementConfigModel(
+ users,
+ '',
+ projects,
+ [...shapes, ...gpuTypes, ...gpuCounts],
+ statuses, resources, endpoints
+ );
}
public openNotebookDetails(data) {
@@ -352,7 +358,10 @@ export class ManagementGridComponent implements OnInit, AfterViewInit, AfterView
selector: 'confirm-dialog',
template: `
<div class="dialog-header">
- <h4 class="modal-title"><span class="capitalize">{{ data.action }}</span> resource</h4>
+ <h4 class="modal-title">
+ <span class="capitalize">{{ data.action }}</span>
+ <span *ngIf="data.action !== 'create image'"> resource</span>
+ </h4>
<button type="button" class="close" (click)="dialogRef.close()">×</button>
</div>
<div mat-dialog-content class="content">
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
index d6c414c58..f7d3179d0 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
@@ -29,7 +29,7 @@ import {
StorageService
} from '../../core/services';
-import { ActionsType, EnvironmentModel, GeneralEnvironmentStatus, ModalData, ModalDataType } from './management.model';
+import {ActionsType, ActionTypeOptions, EnvironmentModel, GeneralEnvironmentStatus, ModalData, ModalDataType} from './management.model';
import { HTTP_STATUS_CODES } from '../../core/util';
import { BackupDilogComponent } from './backup-dilog/backup-dilog.component';
import { SsnMonitorComponent } from './ssn-monitor/ssn-monitor.component';
@@ -43,6 +43,7 @@ import { ConfirmationDialogComponent, ConfirmationDialogType } from '../../share
import { ManagementGridComponent, ReconfirmationDialogComponent } from './management-grid/management-grid.component';
import { FolderTreeComponent } from '../../resources/bucket-browser/folder-tree/folder-tree.component';
import { StatusTypes } from '../../core/models';
+import {AmiCreateDialogComponent} from '../../resources/exploratory/ami-create-dialog';
@Component({
selector: 'environments-management',
@@ -225,8 +226,7 @@ export class ManagementComponent implements OnInit {
this.isActionsOpen = !this.isActionsOpen;
}
- toggleResourceAction($event): void {
- const { environment, action, resource } = $event;
+ toggleResourceAction({ environment, action, resource = null}): void {
this.openDialog(environment, action, resource);
}
@@ -239,7 +239,7 @@ export class ManagementComponent implements OnInit {
}
}
- public resourceAction(action) {
+ public resourceAction(action: ActionTypeOptions) {
this.toggleResourceAction({ environment: this.selected, action: action });
}
@@ -265,7 +265,14 @@ export class ManagementComponent implements OnInit {
observer.next = (res) => {
if (res) {
notebooks.forEach((env) => {
- this.getNotebookAction(env, action);
+ if (action === 'create image') {
+ env['isAdmin'] = true;
+ env['userName'] = env.user;
+ this.dialog.open(AmiCreateDialogComponent, { data: env, panelClass: 'modal-sm' })
+ .afterClosed().subscribe();
+ } else {
+ this.getNotebookAction(env, action);
+ }
});
}
this.clearSelection();
@@ -306,7 +313,7 @@ export class ManagementComponent implements OnInit {
return {...config, notebooks};
}
- private getNotebookAction(env: EnvironmentModel, action: ActionsType) {
+ private getNotebookAction(env: EnvironmentModel, action: ActionsType): void {
this.manageEnvironmentsService.environmentManagement(env.user, action, env.project, env.name)
.subscribe(
() => this.buildGrid(),
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
index 56ce00ff7..5e7435302 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
@@ -117,10 +117,10 @@ export class ManagementConfigModel {
export interface ModalData {
action: ActionsType;
- resource_name?: any;
- user?: any,
+ resource_name?: any;
+ user?: any;
type: string;
- notebooks?: any
+ notebooks?: any;
}
export enum ModalDataType {
@@ -133,5 +133,8 @@ export enum ActionsType {
terminate = 'terminate',
start = 'start',
run = 'run',
- recreate = 'recreate'
-}
\ No newline at end of file
+ recreate = 'recreate',
+ createImage = 'create image'
+}
+
+export type ActionTypeOptions = 'stop' | 'terminate' | 'start' | 'run' | 'recreate' | 'createAmi';
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/pipes/convert-action-type-pipe/convert-action-type.pipe.ts b/services/self-service/src/main/resources/webapp/src/app/core/pipes/convert-action-type-pipe/convert-action-type.pipe.ts
index e1459fcf3..1c47afc10 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/pipes/convert-action-type-pipe/convert-action-type.pipe.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/pipes/convert-action-type-pipe/convert-action-type.pipe.ts
@@ -22,27 +22,31 @@ import { ActionsType } from '../../../administration/management/management.model
const actionTypes = {
stopped: 'Stopped',
- terminated: ' Terminated',
- started: 'Started'
-}
+ terminated: 'Terminated',
+ started: 'Starting',
+ creating: 'Creating Image',
+ unknown: 'Unknown type'
+};
@Pipe({ name: 'convertactiontype' })
export class ConvertActionTypePipe implements PipeTransform {
- transform(value: string,): string {
- if(value === ActionsType.stop) {
- return actionTypes.stopped
+ transform(value: string): string {
+ if (value === ActionsType.stop) {
+ return actionTypes.stopped;
}
- if(value === ActionsType.start) {
- return actionTypes.started
+ if (value === ActionsType.start) {
+ return actionTypes.started;
}
- if(value === ActionsType.terminate) {
- return actionTypes.terminated
+ if (value === ActionsType.terminate) {
+ return actionTypes.terminated;
}
- else {
- return 'Unknown type'
+ if (value === ActionsType.createImage) {
+ return actionTypes.creating;
+ } else {
+ return actionTypes.unknown;
}
}
}
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts b/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts
index 3bb326d3e..13167f3eb 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/services/applicationServiceFacade.service.ts
@@ -475,7 +475,7 @@ export class ApplicationServiceFacade {
data,
{
observe: 'response',
- headers: { 'Content-Type': 'text/plain' }
+ headers: { 'Content-Type': 'application/json; charset=UTF-8' }
});
}
@@ -805,4 +805,4 @@ export class ApplicationServiceFacade {
return this.http.get(body ? (url + body) : url, opt);
}
}
-}
\ No newline at end of file
+}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html
index ae576f2d9..a5befe290 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html
@@ -45,19 +45,19 @@
</div>
</form>
<div class="text-center m-top-30 m-bott-10">
- <button
- mat-raised-button
- type="button"
- class="butt action"
+ <button
+ mat-raised-button
+ type="button"
+ class="butt action"
(click)="dialogRef.close()"
>
Cancel
</button>
- <button
- mat-raised-button
- type="button"
+ <button
+ mat-raised-button
+ type="button"
[disabled]="!createAMIForm.valid"
- (click)="assignChanges(createAMIForm.value)"
+ (click)="assignChanges(createAMIForm.value)"
class="butt butt-success action"
>
Create
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts
index 315f8f3c6..455468a28 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts
@@ -22,7 +22,7 @@ import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { ToastrService } from 'ngx-toastr';
-import { UserResourceService } from '../../../core/services';
+import {ManageEnvironmentsService, UserResourceService} from '../../../core/services';
import { HTTP_STATUS_CODES, PATTERNS } from '../../../core/util';
import { DICTIONARY } from '../../../../dictionary/global.dictionary';
@@ -38,6 +38,7 @@ export class AmiCreateDialogComponent implements OnInit {
public provider: string;
delimitersRegex = /[-_]?/g;
imagesList: any;
+ private isAdmin: boolean = false;
constructor(
@Inject(MAT_DIALOG_DATA) public data: any,
@@ -45,28 +46,43 @@ export class AmiCreateDialogComponent implements OnInit {
public dialogRef: MatDialogRef<AmiCreateDialogComponent>,
private _userResource: UserResourceService,
private _fb: FormBuilder,
+ private manageEnvironmentsService: ManageEnvironmentsService,
) { }
ngOnInit() {
this.notebook = this.data;
this.provider = this.data.cloud_provider;
+ this.checkRole();
this.initFormModel();
this._userResource.getImagesList(this.data.project).subscribe(res => this.imagesList = res);
}
- public assignChanges(data) {
- this._userResource.createAMI(data).subscribe(
- response => response.status === HTTP_STATUS_CODES.ACCEPTED && this.dialogRef.close(true),
- error => this.toastr.error(error.message || `Image creation failed!`, 'Oops!'));
+ public assignChanges(data): void {
+ if (this.isAdmin) {
+ const { exploratory_name, project_name, name, description } = data;
+ const imageInfo = { user: this.data.userName, imageName: name, description, project_name, exploratory_name};
+ this.manageEnvironmentsService.environmentManagement(imageInfo, 'createImage', project_name, exploratory_name).subscribe(
+ () => { this.dialogRef.close(true); });
+ } else {
+ this._userResource.createAMI(data).subscribe(
+ response => response.status === HTTP_STATUS_CODES.ACCEPTED && this.dialogRef.close(true),
+ error => this.toastr.error(error.message || `Image creation failed!`, 'Oops!'));
+ }
+ }
+
+ private checkRole(): void {
+ if (this.data?.isAdmin) {
+ this.isAdmin = this.data.isAdmin;
+ }
}
private initFormModel(): void {
this.createAMIForm = this._fb.group({
name: ['', [
- Validators.required,
- Validators.pattern(PATTERNS.namePattern),
- Validators.maxLength(10),
+ Validators.required,
+ Validators.pattern(PATTERNS.namePattern),
+ Validators.maxLength(10),
this.checkDuplication.bind(this)
]],
description: [''],
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datalab.apache.org
For additional commands, e-mail: commits-help@datalab.apache.org
[incubator-datalab] 03/09: [DATALAB-2771] created create image btn
Posted by dy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
dyankiv pushed a commit to branch DATALAB-2785
in repository https://gitbox.apache.org/repos/asf/incubator-datalab.git
commit a29aa062260ea11a43103233140c05181a059303
Author: Hennadii_Shpak <bo...@gmail.com>
AuthorDate: Tue May 3 18:18:27 2022 +0300
[DATALAB-2771] created create image btn
---
.../management-grid/management-grid.component.html | 221 +++++++++++----------
.../management-grid/management-grid.component.ts | 47 +++--
.../management/management.component.ts | 19 +-
.../administration/management/management.model.ts | 13 +-
.../convert-action-type.pipe.ts | 28 +--
.../ami-create-dialog.component.html | 16 +-
.../ami-create-dialog.component.ts | 32 ++-
7 files changed, 213 insertions(+), 163 deletions(-)
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
index c8c793d8c..43c7534ee 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
@@ -18,14 +18,14 @@
-->
<div class="managment-wrapper scrolling" #pageWrapper (scroll)="scrollTable($event)" (resize)="onResize($event)">
<div class="ani scrolling scroll-wrapper" #wrapper (scroll)="scrollTable($event)">
- <div
- class="nav-buttons"
+ <div
+ class="nav-buttons"
[ngStyle]="{'width.px': userAgentIndex === -1 ? tableWrapperWidth - 3 : tableWrapperWidth - 7 }"
- [ngClass]="{'border': tableEl['offsetHeight'] < tableWrapper.offsetHeight - 48}"
+ [ngClass]="{'border': tableEl['offsetHeight'] < tableWrapper.offsetHeight - 48}"
[hidden]="!(tableWrapper.offsetWidth - tableEl['offsetWidth'] < 0)"
>
<div class="button-container">
- <button
+ <button
mat-mini-fab aria-label="Scroll left"
(click)="sctollTo('left')"
[ngClass]="{'not-allowed': wrapper.scrollLeft === 0 }"
@@ -34,7 +34,7 @@
</button>
</div>
<div class="button-container" [ngClass]="{'not-allowed': checkMaxRight()}">
- <button
+ <button
mat-mini-fab aria-label="Scroll right"
(click)="sctollTo('right')"
[ngClass]="{'not-allowed': !(isMaxRight | async)}"
@@ -61,10 +61,10 @@
</button>
</th>
<td mat-cell *matCellDef="let element">
- <ng-template
- [ngIf]="element.type !== 'odahu'
- && element.type !== 'edge node'
- && (element.status==='running' || element.status==='stopped')
+ <ng-template
+ [ngIf]="element.type !== 'odahu'
+ && element.type !== 'edge node'
+ && (element.status==='running' || element.status==='stopped')
&& !clustersInProgress(element.resources)"
>
<datalab-checkbox
@@ -79,10 +79,10 @@
<ng-container matColumnDef="user">
<th mat-header-cell *matHeaderCellDef class="user label-header">
<span class="label">User</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -105,17 +105,17 @@
<ng-container matColumnDef="project">
<th mat-header-cell *matHeaderCellDef class="project label-header">
<span class="label">Project</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
<span *ngIf="filtering && filterForm.projects.length > 0 && !collapsedFilterRow">filter_list</span>
<span [hidden]="filtering && filterForm.projects.length > 0 && !collapsedFilterRow">more_vert</span>
</i>
- </button>
+ </button>
</th>
<td mat-cell *matCellDef="let element">{{ element.project }}</td>
</ng-container>
@@ -123,10 +123,10 @@
<ng-container matColumnDef="endpoint">
<th mat-header-cell *matHeaderCellDef class="endpoint label-header">
<span class="label">Endpoint</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -141,10 +141,10 @@
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef class="type label-header">
<span class="label">Name</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -168,10 +168,10 @@
<ng-container matColumnDef="shape">
<th mat-header-cell *matHeaderCellDef class="shape label-header">
<span class="label">Shape / Resource id</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -190,10 +190,10 @@
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef class="status label-header">
<span class="label">Status</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -210,10 +210,10 @@
<ng-container matColumnDef="resources">
<th mat-header-cell *matHeaderCellDef class="resources label-header">
<span class="label">Compute</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -236,8 +236,8 @@
<div class="resource-actions">
<span class="not-allow">
<a class="start-stop-action" *ngIf="resource.image === 'docker.datalab-dataengine'">
- <i
- class="material-icons"
+ <i
+ class="material-icons"
(click)="toggleResourceAction(element, 'stop', resource)"
[ngClass]="{'not-allowed' : resource.status !== 'running' || selected?.length }"
>
@@ -246,8 +246,8 @@
</a>
</span>
<span class="not-allow">
- <a
- class="remove_butt"
+ <a
+ class="remove_butt"
(click)="toggleResourceAction(element, 'terminate', resource)"
[ngClass]="{ 'disabled' : element.status !== 'running' || (resource.status !== 'running' && resource.status !== 'stopped') || selected?.length }"
>
@@ -267,10 +267,10 @@
</th>
<td mat-cell *matCellDef="let element" class="settings actions-col">
<span [ngClass]="{'not-allow' : selected?.length}">
- <span
- #settings
- class="actions"
- (click)="actions.toggle($event, settings)"
+ <span
+ #settings
+ class="actions"
+ (click)="actions.toggle($event, settings)"
*ngIf="element.type !== 'edge node' && element.type !== 'odahu'"
[ngClass]="{
'disabled' : (element.status !== 'running' && element.status !== 'stopped')
@@ -281,39 +281,50 @@
<bubble-up #actions class="list-menu" position="bottom-left" alternative="top-left">
<ul class="list-unstyled">
<li
- matTooltip="{{ element.type !== 'edge node'
- ? 'Unable to stop notebook because at least one computational resource is in progress'
+ matTooltip="{{ element.type !== 'edge node'
+ ? 'Unable to stop notebook because at least one computational resource is in progress'
: 'Unable to stop edge node because at least one resource of this user is in progress' }}"
- matTooltipPosition="above"
+ matTooltipPosition="above"
[matTooltipDisabled]="!isResourcesInProgress(element)"
[hidden]="element.name === 'edge node' && element.status === 'stopped'"
>
- <div
+ <div
(click)="toggleResourceAction(element, 'stop')"
- [ngClass]="{'not-allowed' : element.status === 'stopped' || element.status === 'stopping' ||
- element.status === 'starting' || element.status === 'creating image' ||
+ [ngClass]="{'not-allowed' : element.status === 'stopped' || element.status === 'stopping' ||
+ element.status === 'starting' || element.status === 'creating image' ||
element.status === 'failed' || isResourcesInProgress(element)}"
>
<i class="material-icons">pause_circle_outline</i>
<span>Stop</span>
</div>
</li>
- <li
+ <li
*ngIf="element.name !== 'edge node'"
matTooltip="Unable to terminate notebook because at least one compute is in progress"
- matTooltipPosition="above"
+ matTooltipPosition="above"
[matTooltipDisabled]="!isResourcesInProgress(element)"
>
- <div
+ <div
(click)="toggleResourceAction(element, 'terminate')"
- [ngClass]="{'not-allowed' : element.status !== 'running' &&
- element.status !== 'stopped' ||
+ [ngClass]="{'not-allowed' : element.status !== 'running' &&
+ element.status !== 'stopped' ||
isResourcesInProgress(element)}"
>
<i class="material-icons">phonelink_off</i>
<span>Terminate</span>
</div>
</li>
+ <li
+ *ngIf="element.status !== 'terminated' && element.image !== 'docker.datalab-superset'
+ && element.image !== 'docker.datalab-jupyterlab'"
+ >
+ <div
+ (click)="toggleResourceAction(element, 'create image')"
+ >
+ <i class="material-icons">view_module</i>
+ <span>Create Image</span>
+ </div>
+ </li>
<li *ngIf="element.status === 'stopped'">
<div (click)="toggleResourceAction(element, 'start')">
<i class="material-icons">play_circle_outline</i>
@@ -333,9 +344,9 @@
<ng-container matColumnDef="user-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
- [type]="'users'"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
+ [type]="'users'"
[items]="filterConfiguration.users"
[model]="filterForm.users"
></multi-select-dropdown>
@@ -344,11 +355,11 @@
<ng-container matColumnDef="type-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <input
- placeholder="Filter by name"
- type="text"
+ <input
+ placeholder="Filter by name"
+ type="text"
class="form-control filter-field"
- [value]="filterForm.type"
+ [value]="filterForm.type"
(input)="onFilterNameUpdate($event.target['value'])"
/>
</th>
@@ -356,20 +367,20 @@
<ng-container matColumnDef="project-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'projects'"
- [items]="filterConfiguration.projects"
+ [items]="filterConfiguration.projects"
[model]="filterForm.projects"
></multi-select-dropdown>
</th>
</ng-container>
<ng-container matColumnDef="endpoint-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'endpoints'"
- [items]="filterConfiguration.endpoints"
+ [items]="filterConfiguration.endpoints"
[model]="filterForm.endpoints"
></multi-select-dropdown>
</th>
@@ -377,10 +388,10 @@
<ng-container matColumnDef="shape-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'shapes'"
- [items]="filterConfiguration.shapes"
+ [items]="filterConfiguration.shapes"
[model]="filterForm.shapes"
></multi-select-dropdown>
</th>
@@ -388,10 +399,10 @@
<ng-container matColumnDef="status-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'statuses'"
- [items]="filterConfiguration.statuses"
+ [items]="filterConfiguration.statuses"
[model]="filterForm.statuses"
></multi-select-dropdown>
</th>
@@ -399,10 +410,10 @@
<ng-container matColumnDef="resource-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'resources'"
- [items]="filterConfiguration.resources"
+ [items]="filterConfiguration.resources"
[model]="filterForm.resources"
></multi-select-dropdown>
</th>
@@ -411,22 +422,22 @@
<ng-container matColumnDef="actions-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="actions-col filter-row-item">
<div class="actions">
- <button
- mat-icon-button
- class="btn reset"
- (click)="resetFilterConfigurations()"
+ <button
+ mat-icon-button
+ class="btn reset"
+ (click)="resetFilterConfigurations()"
[disabled]="!isFilterSelected"
>
<i class="material-icons">close</i>
</button>
- <button
- mat-icon-button
- class="btn apply"
+ <button
+ mat-icon-button
+ class="btn apply"
(click)="applyFilter(filterForm)"
[disabled]="isFilterChanged"
>
- <i
+ <i
class="material-icons"
[ngClass]="{'not-allowed': allFilteredEnvironmentData?.length == 0 && !filtering}"
>
@@ -439,7 +450,7 @@
<ng-container matColumnDef="placeholder">
<td mat-footer-cell *matFooterCellDef colspan="8" class="no-border">
- <div
+ <div
class="info"
*ngIf="(!allFilteredEnvironmentData) && !filtering || (allFilteredEnvironmentData?.length == 0) && !filtering"
>
@@ -450,36 +461,36 @@
</ng-container>
<ng-container matColumnDef="scrollButtons">
- <td
- mat-footer-cell
- *matFooterCellDef
- colspan="9"
+ <td
+ mat-footer-cell
+ *matFooterCellDef
+ colspan="9"
class="buttons-wrap"
></td>
</ng-container>
- <tr
- mat-header-row
- *matHeaderRowDef="displayedColumns; sticky: true"
+ <tr
+ mat-header-row
+ *matHeaderRowDef="displayedColumns; sticky: true"
class="header-row"
></tr>
- <tr
- [hidden]="!collapsedFilterRow"
- mat-header-row
+ <tr
+ [hidden]="!collapsedFilterRow"
+ mat-header-row
*matHeaderRowDef="displayedFilterColumns; sticky: true"
class="filter-row"
></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
- <tr
- [hidden]="allFilteredEnvironmentData?.length"
- mat-footer-row *matFooterRowDef="['placeholder']"
+ <tr
+ [hidden]="allFilteredEnvironmentData?.length"
+ mat-footer-row *matFooterRowDef="['placeholder']"
class="info"
></tr>
- <tr
- [hidden]="!tableEl || !tableEl['offsetWidth'] || tableWrapper.offsetWidth - tableEl['offsetWidth'] > -16 || !allFilteredEnvironmentData?.length"
- mat-footer-row
- *matFooterRowDef="['scrollButtons']; sticky: true"
+ <tr
+ [hidden]="!tableEl || !tableEl['offsetWidth'] || tableWrapper.offsetWidth - tableEl['offsetWidth'] > -16 || !allFilteredEnvironmentData?.length"
+ mat-footer-row
+ *matFooterRowDef="['scrollButtons']; sticky: true"
class="info"
></tr>
</table>
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
index a122af1c6..d757eedac 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
@@ -142,7 +142,7 @@ export class ManagementGridComponent implements OnInit, AfterViewInit, AfterView
this.applyFilter(this.cashedFilterForm || this.filterForm);
}
this.progressBarService.stopProgressBar();
- },
+ },
() => {
this.progressBarService.stopProgressBar();
}
@@ -186,8 +186,8 @@ export class ManagementGridComponent implements OnInit, AfterViewInit, AfterView
const containsStatus = (list, selectedItems) => {
if (list) {
- return list.filter((item: any) => {
- if (selectedItems.indexOf(item.status) !== -1) return item;
+ return list.filter((item: any) => {
+ if (selectedItems.indexOf(item.status) !== -1) return item;
});
}
};
@@ -196,30 +196,30 @@ export class ManagementGridComponent implements OnInit, AfterViewInit, AfterView
if (config) {
filteredData = filteredData.filter(item => {
const isUser = config.users.length > 0 ? (config.users.indexOf(item.user) !== -1) : true;
- const isTypeName = item.name
- ? item.name.toLowerCase().indexOf(config.type.toLowerCase()) !== -1
+ const isTypeName = item.name
+ ? item.name.toLowerCase().indexOf(config.type.toLowerCase()) !== -1
: item.type.toLowerCase().indexOf(config.type.toLowerCase()) !== -1;
- const isStatus = config.statuses.length > 0
- ? (config.statuses.indexOf(item.status) !== -1)
+ const isStatus = config.statuses.length > 0
+ ? (config.statuses.indexOf(item.status) !== -1)
: (config.type !== 'active');
- const isShape = config.shapes.length > 0
+ const isShape = config.shapes.length > 0
? (config.shapes.indexOf(item.shape) !== -1 ||
config.shapes.indexOf(item.gpu_type) !== -1 ||
- config.shapes.indexOf(`GPU count: ${item.gpu_count}`) !== -1)
+ config.shapes.indexOf(`GPU count: ${item.gpu_count}`) !== -1)
: true;
- const isProject = config.projects.length > 0
- ? (config.projects.indexOf(item.project) !== -1)
+ const isProject = config.projects.length > 0
+ ? (config.projects.indexOf(item.project) !== -1)
: true;
- const isEndpoint = config.endpoints.length > 0
- ? (config.endpoints.indexOf(item.endpoint) !== -1)
+ const isEndpoint = config.endpoints.length > 0
+ ? (config.endpoints.indexOf(item.endpoint) !== -1)
: true;
const modifiedResources = containsStatus(item.resources, config.resources);
- let isResources = config.resources.length > 0
- ? (modifiedResources && modifiedResources.length > 0)
+ let isResources = config.resources.length > 0
+ ? (modifiedResources && modifiedResources.length > 0)
: true;
- if (config.resources.length > 0 && modifiedResources && modifiedResources.length > 0) {
- item.resources = modifiedResources;
+ if (config.resources.length > 0 && modifiedResources && modifiedResources.length > 0) {
+ item.resources = modifiedResources;
}
if (config.resources && config.resources.length === 0 && config.type === 'active' ||
@@ -288,7 +288,13 @@ export class ManagementGridComponent implements OnInit, AfterViewInit, AfterView
}
});
- this.filterConfiguration = new ManagementConfigModel(users, '', projects, [...shapes, ...gpuTypes, ...gpuCounts], statuses, resources, endpoints);
+ this.filterConfiguration = new ManagementConfigModel(
+ users,
+ '',
+ projects,
+ [...shapes, ...gpuTypes, ...gpuCounts],
+ statuses, resources, endpoints
+ );
}
public openNotebookDetails(data) {
@@ -352,7 +358,10 @@ export class ManagementGridComponent implements OnInit, AfterViewInit, AfterView
selector: 'confirm-dialog',
template: `
<div class="dialog-header">
- <h4 class="modal-title"><span class="capitalize">{{ data.action }}</span> resource</h4>
+ <h4 class="modal-title">
+ <span class="capitalize">{{ data.action }}</span>
+ <span *ngIf="data.action !== 'create image'"> resource</span>
+ </h4>
<button type="button" class="close" (click)="dialogRef.close()">×</button>
</div>
<div mat-dialog-content class="content">
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
index d6c414c58..4dd9de2ac 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
@@ -29,7 +29,7 @@ import {
StorageService
} from '../../core/services';
-import { ActionsType, EnvironmentModel, GeneralEnvironmentStatus, ModalData, ModalDataType } from './management.model';
+import {ActionsType, ActionTypeOptions, EnvironmentModel, GeneralEnvironmentStatus, ModalData, ModalDataType} from './management.model';
import { HTTP_STATUS_CODES } from '../../core/util';
import { BackupDilogComponent } from './backup-dilog/backup-dilog.component';
import { SsnMonitorComponent } from './ssn-monitor/ssn-monitor.component';
@@ -43,6 +43,7 @@ import { ConfirmationDialogComponent, ConfirmationDialogType } from '../../share
import { ManagementGridComponent, ReconfirmationDialogComponent } from './management-grid/management-grid.component';
import { FolderTreeComponent } from '../../resources/bucket-browser/folder-tree/folder-tree.component';
import { StatusTypes } from '../../core/models';
+import {AmiCreateDialogComponent} from '../../resources/exploratory/ami-create-dialog';
@Component({
selector: 'environments-management',
@@ -225,8 +226,7 @@ export class ManagementComponent implements OnInit {
this.isActionsOpen = !this.isActionsOpen;
}
- toggleResourceAction($event): void {
- const { environment, action, resource } = $event;
+ toggleResourceAction({ environment, action, resource = null}): void {
this.openDialog(environment, action, resource);
}
@@ -239,7 +239,7 @@ export class ManagementComponent implements OnInit {
}
}
- public resourceAction(action) {
+ public resourceAction(action: ActionTypeOptions) {
this.toggleResourceAction({ environment: this.selected, action: action });
}
@@ -265,7 +265,14 @@ export class ManagementComponent implements OnInit {
observer.next = (res) => {
if (res) {
notebooks.forEach((env) => {
- this.getNotebookAction(env, action);
+ if (action === 'Create Image') {
+ env['isAdmin'] = true;
+ env['userName'] = env.user;
+ this.dialog.open(AmiCreateDialogComponent, { data: env, panelClass: 'modal-sm' })
+ .afterClosed().subscribe();
+ } else {
+ this.getNotebookAction(env, action);
+ }
});
}
this.clearSelection();
@@ -306,7 +313,7 @@ export class ManagementComponent implements OnInit {
return {...config, notebooks};
}
- private getNotebookAction(env: EnvironmentModel, action: ActionsType) {
+ private getNotebookAction(env: EnvironmentModel, action: ActionsType): void {
this.manageEnvironmentsService.environmentManagement(env.user, action, env.project, env.name)
.subscribe(
() => this.buildGrid(),
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
index 56ce00ff7..5e7435302 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
@@ -117,10 +117,10 @@ export class ManagementConfigModel {
export interface ModalData {
action: ActionsType;
- resource_name?: any;
- user?: any,
+ resource_name?: any;
+ user?: any;
type: string;
- notebooks?: any
+ notebooks?: any;
}
export enum ModalDataType {
@@ -133,5 +133,8 @@ export enum ActionsType {
terminate = 'terminate',
start = 'start',
run = 'run',
- recreate = 'recreate'
-}
\ No newline at end of file
+ recreate = 'recreate',
+ createImage = 'create image'
+}
+
+export type ActionTypeOptions = 'stop' | 'terminate' | 'start' | 'run' | 'recreate' | 'createAmi';
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/pipes/convert-action-type-pipe/convert-action-type.pipe.ts b/services/self-service/src/main/resources/webapp/src/app/core/pipes/convert-action-type-pipe/convert-action-type.pipe.ts
index e1459fcf3..1c47afc10 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/pipes/convert-action-type-pipe/convert-action-type.pipe.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/pipes/convert-action-type-pipe/convert-action-type.pipe.ts
@@ -22,27 +22,31 @@ import { ActionsType } from '../../../administration/management/management.model
const actionTypes = {
stopped: 'Stopped',
- terminated: ' Terminated',
- started: 'Started'
-}
+ terminated: 'Terminated',
+ started: 'Starting',
+ creating: 'Creating Image',
+ unknown: 'Unknown type'
+};
@Pipe({ name: 'convertactiontype' })
export class ConvertActionTypePipe implements PipeTransform {
- transform(value: string,): string {
- if(value === ActionsType.stop) {
- return actionTypes.stopped
+ transform(value: string): string {
+ if (value === ActionsType.stop) {
+ return actionTypes.stopped;
}
- if(value === ActionsType.start) {
- return actionTypes.started
+ if (value === ActionsType.start) {
+ return actionTypes.started;
}
- if(value === ActionsType.terminate) {
- return actionTypes.terminated
+ if (value === ActionsType.terminate) {
+ return actionTypes.terminated;
}
- else {
- return 'Unknown type'
+ if (value === ActionsType.createImage) {
+ return actionTypes.creating;
+ } else {
+ return actionTypes.unknown;
}
}
}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html
index ae576f2d9..a5befe290 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html
@@ -45,19 +45,19 @@
</div>
</form>
<div class="text-center m-top-30 m-bott-10">
- <button
- mat-raised-button
- type="button"
- class="butt action"
+ <button
+ mat-raised-button
+ type="button"
+ class="butt action"
(click)="dialogRef.close()"
>
Cancel
</button>
- <button
- mat-raised-button
- type="button"
+ <button
+ mat-raised-button
+ type="button"
[disabled]="!createAMIForm.valid"
- (click)="assignChanges(createAMIForm.value)"
+ (click)="assignChanges(createAMIForm.value)"
class="butt butt-success action"
>
Create
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts
index 315f8f3c6..c5caebc00 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts
@@ -22,7 +22,7 @@ import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { ToastrService } from 'ngx-toastr';
-import { UserResourceService } from '../../../core/services';
+import {ManageEnvironmentsService, UserResourceService} from '../../../core/services';
import { HTTP_STATUS_CODES, PATTERNS } from '../../../core/util';
import { DICTIONARY } from '../../../../dictionary/global.dictionary';
@@ -38,6 +38,7 @@ export class AmiCreateDialogComponent implements OnInit {
public provider: string;
delimitersRegex = /[-_]?/g;
imagesList: any;
+ private isAdmin: boolean = false;
constructor(
@Inject(MAT_DIALOG_DATA) public data: any,
@@ -45,28 +46,43 @@ export class AmiCreateDialogComponent implements OnInit {
public dialogRef: MatDialogRef<AmiCreateDialogComponent>,
private _userResource: UserResourceService,
private _fb: FormBuilder,
+ private manageEnvironmentsService: ManageEnvironmentsService,
) { }
ngOnInit() {
this.notebook = this.data;
this.provider = this.data.cloud_provider;
+ this.checkRole();
this.initFormModel();
this._userResource.getImagesList(this.data.project).subscribe(res => this.imagesList = res);
}
- public assignChanges(data) {
- this._userResource.createAMI(data).subscribe(
- response => response.status === HTTP_STATUS_CODES.ACCEPTED && this.dialogRef.close(true),
- error => this.toastr.error(error.message || `Image creation failed!`, 'Oops!'));
+ public assignChanges(data): void {
+ if (this.isAdmin) {
+ const { exploratory_name, project_name, name, description } = data;
+ const imageInfo = { userName: this.data.userName, imageName: name, description};
+ this.manageEnvironmentsService.environmentManagement(imageInfo, 'createAmi', project_name, exploratory_name).subscribe(
+ () => { this.dialogRef.close(true); });
+ } else {
+ this._userResource.createAMI(data).subscribe(
+ response => response.status === HTTP_STATUS_CODES.ACCEPTED && this.dialogRef.close(true),
+ error => this.toastr.error(error.message || `Image creation failed!`, 'Oops!'));
+ }
+ }
+
+ private checkRole(): void {
+ if (this.data?.isAdmin) {
+ this.isAdmin = this.data.isAdmin;
+ }
}
private initFormModel(): void {
this.createAMIForm = this._fb.group({
name: ['', [
- Validators.required,
- Validators.pattern(PATTERNS.namePattern),
- Validators.maxLength(10),
+ Validators.required,
+ Validators.pattern(PATTERNS.namePattern),
+ Validators.maxLength(10),
this.checkDuplication.bind(this)
]],
description: [''],
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datalab.apache.org
For additional commands, e-mail: commits-help@datalab.apache.org
[incubator-datalab] 04/09: resolve conflict
Posted by dy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
dyankiv pushed a commit to branch DATALAB-2785
in repository https://gitbox.apache.org/repos/asf/incubator-datalab.git
commit e6a9f09a41ae1a5847e7b9d9b642041404946af6
Merge: ac1a9a61d a29aa0622
Author: Denys Yankiv <de...@gmail.com>
AuthorDate: Thu May 12 13:54:13 2022 +0300
resolve conflict
.../management-grid/management-grid.component.html | 4 ++--
.../management-grid/management-grid.component.ts | 5 +++-
.../administration/management/management.model.ts | 2 +-
.../convert-action-type.pipe.ts | 28 ++++++++++++----------
4 files changed, 23 insertions(+), 16 deletions(-)
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datalab.apache.org
For additional commands, e-mail: commits-help@datalab.apache.org
[incubator-datalab] 05/09: [DATALAB-2771] created create image btn
Posted by dy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
dyankiv pushed a commit to branch DATALAB-2785
in repository https://gitbox.apache.org/repos/asf/incubator-datalab.git
commit ae8007f5dc8359543821855f3da08b42438ad224
Author: Hennadii_Shpak <bo...@gmail.com>
AuthorDate: Tue May 3 18:18:27 2022 +0300
[DATALAB-2771] created create image btn
---
.../management-grid/management-grid.component.html | 221 +++++++++++----------
.../management-grid/management-grid.component.ts | 47 +++--
.../management/management.component.ts | 19 +-
.../administration/management/management.model.ts | 13 +-
.../convert-action-type.pipe.ts | 28 +--
.../ami-create-dialog.component.html | 16 +-
.../ami-create-dialog.component.ts | 32 ++-
7 files changed, 213 insertions(+), 163 deletions(-)
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
index c8c793d8c..43c7534ee 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
@@ -18,14 +18,14 @@
-->
<div class="managment-wrapper scrolling" #pageWrapper (scroll)="scrollTable($event)" (resize)="onResize($event)">
<div class="ani scrolling scroll-wrapper" #wrapper (scroll)="scrollTable($event)">
- <div
- class="nav-buttons"
+ <div
+ class="nav-buttons"
[ngStyle]="{'width.px': userAgentIndex === -1 ? tableWrapperWidth - 3 : tableWrapperWidth - 7 }"
- [ngClass]="{'border': tableEl['offsetHeight'] < tableWrapper.offsetHeight - 48}"
+ [ngClass]="{'border': tableEl['offsetHeight'] < tableWrapper.offsetHeight - 48}"
[hidden]="!(tableWrapper.offsetWidth - tableEl['offsetWidth'] < 0)"
>
<div class="button-container">
- <button
+ <button
mat-mini-fab aria-label="Scroll left"
(click)="sctollTo('left')"
[ngClass]="{'not-allowed': wrapper.scrollLeft === 0 }"
@@ -34,7 +34,7 @@
</button>
</div>
<div class="button-container" [ngClass]="{'not-allowed': checkMaxRight()}">
- <button
+ <button
mat-mini-fab aria-label="Scroll right"
(click)="sctollTo('right')"
[ngClass]="{'not-allowed': !(isMaxRight | async)}"
@@ -61,10 +61,10 @@
</button>
</th>
<td mat-cell *matCellDef="let element">
- <ng-template
- [ngIf]="element.type !== 'odahu'
- && element.type !== 'edge node'
- && (element.status==='running' || element.status==='stopped')
+ <ng-template
+ [ngIf]="element.type !== 'odahu'
+ && element.type !== 'edge node'
+ && (element.status==='running' || element.status==='stopped')
&& !clustersInProgress(element.resources)"
>
<datalab-checkbox
@@ -79,10 +79,10 @@
<ng-container matColumnDef="user">
<th mat-header-cell *matHeaderCellDef class="user label-header">
<span class="label">User</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -105,17 +105,17 @@
<ng-container matColumnDef="project">
<th mat-header-cell *matHeaderCellDef class="project label-header">
<span class="label">Project</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
<span *ngIf="filtering && filterForm.projects.length > 0 && !collapsedFilterRow">filter_list</span>
<span [hidden]="filtering && filterForm.projects.length > 0 && !collapsedFilterRow">more_vert</span>
</i>
- </button>
+ </button>
</th>
<td mat-cell *matCellDef="let element">{{ element.project }}</td>
</ng-container>
@@ -123,10 +123,10 @@
<ng-container matColumnDef="endpoint">
<th mat-header-cell *matHeaderCellDef class="endpoint label-header">
<span class="label">Endpoint</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -141,10 +141,10 @@
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef class="type label-header">
<span class="label">Name</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -168,10 +168,10 @@
<ng-container matColumnDef="shape">
<th mat-header-cell *matHeaderCellDef class="shape label-header">
<span class="label">Shape / Resource id</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -190,10 +190,10 @@
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef class="status label-header">
<span class="label">Status</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -210,10 +210,10 @@
<ng-container matColumnDef="resources">
<th mat-header-cell *matHeaderCellDef class="resources label-header">
<span class="label">Compute</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -236,8 +236,8 @@
<div class="resource-actions">
<span class="not-allow">
<a class="start-stop-action" *ngIf="resource.image === 'docker.datalab-dataengine'">
- <i
- class="material-icons"
+ <i
+ class="material-icons"
(click)="toggleResourceAction(element, 'stop', resource)"
[ngClass]="{'not-allowed' : resource.status !== 'running' || selected?.length }"
>
@@ -246,8 +246,8 @@
</a>
</span>
<span class="not-allow">
- <a
- class="remove_butt"
+ <a
+ class="remove_butt"
(click)="toggleResourceAction(element, 'terminate', resource)"
[ngClass]="{ 'disabled' : element.status !== 'running' || (resource.status !== 'running' && resource.status !== 'stopped') || selected?.length }"
>
@@ -267,10 +267,10 @@
</th>
<td mat-cell *matCellDef="let element" class="settings actions-col">
<span [ngClass]="{'not-allow' : selected?.length}">
- <span
- #settings
- class="actions"
- (click)="actions.toggle($event, settings)"
+ <span
+ #settings
+ class="actions"
+ (click)="actions.toggle($event, settings)"
*ngIf="element.type !== 'edge node' && element.type !== 'odahu'"
[ngClass]="{
'disabled' : (element.status !== 'running' && element.status !== 'stopped')
@@ -281,39 +281,50 @@
<bubble-up #actions class="list-menu" position="bottom-left" alternative="top-left">
<ul class="list-unstyled">
<li
- matTooltip="{{ element.type !== 'edge node'
- ? 'Unable to stop notebook because at least one computational resource is in progress'
+ matTooltip="{{ element.type !== 'edge node'
+ ? 'Unable to stop notebook because at least one computational resource is in progress'
: 'Unable to stop edge node because at least one resource of this user is in progress' }}"
- matTooltipPosition="above"
+ matTooltipPosition="above"
[matTooltipDisabled]="!isResourcesInProgress(element)"
[hidden]="element.name === 'edge node' && element.status === 'stopped'"
>
- <div
+ <div
(click)="toggleResourceAction(element, 'stop')"
- [ngClass]="{'not-allowed' : element.status === 'stopped' || element.status === 'stopping' ||
- element.status === 'starting' || element.status === 'creating image' ||
+ [ngClass]="{'not-allowed' : element.status === 'stopped' || element.status === 'stopping' ||
+ element.status === 'starting' || element.status === 'creating image' ||
element.status === 'failed' || isResourcesInProgress(element)}"
>
<i class="material-icons">pause_circle_outline</i>
<span>Stop</span>
</div>
</li>
- <li
+ <li
*ngIf="element.name !== 'edge node'"
matTooltip="Unable to terminate notebook because at least one compute is in progress"
- matTooltipPosition="above"
+ matTooltipPosition="above"
[matTooltipDisabled]="!isResourcesInProgress(element)"
>
- <div
+ <div
(click)="toggleResourceAction(element, 'terminate')"
- [ngClass]="{'not-allowed' : element.status !== 'running' &&
- element.status !== 'stopped' ||
+ [ngClass]="{'not-allowed' : element.status !== 'running' &&
+ element.status !== 'stopped' ||
isResourcesInProgress(element)}"
>
<i class="material-icons">phonelink_off</i>
<span>Terminate</span>
</div>
</li>
+ <li
+ *ngIf="element.status !== 'terminated' && element.image !== 'docker.datalab-superset'
+ && element.image !== 'docker.datalab-jupyterlab'"
+ >
+ <div
+ (click)="toggleResourceAction(element, 'create image')"
+ >
+ <i class="material-icons">view_module</i>
+ <span>Create Image</span>
+ </div>
+ </li>
<li *ngIf="element.status === 'stopped'">
<div (click)="toggleResourceAction(element, 'start')">
<i class="material-icons">play_circle_outline</i>
@@ -333,9 +344,9 @@
<ng-container matColumnDef="user-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
- [type]="'users'"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
+ [type]="'users'"
[items]="filterConfiguration.users"
[model]="filterForm.users"
></multi-select-dropdown>
@@ -344,11 +355,11 @@
<ng-container matColumnDef="type-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <input
- placeholder="Filter by name"
- type="text"
+ <input
+ placeholder="Filter by name"
+ type="text"
class="form-control filter-field"
- [value]="filterForm.type"
+ [value]="filterForm.type"
(input)="onFilterNameUpdate($event.target['value'])"
/>
</th>
@@ -356,20 +367,20 @@
<ng-container matColumnDef="project-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'projects'"
- [items]="filterConfiguration.projects"
+ [items]="filterConfiguration.projects"
[model]="filterForm.projects"
></multi-select-dropdown>
</th>
</ng-container>
<ng-container matColumnDef="endpoint-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'endpoints'"
- [items]="filterConfiguration.endpoints"
+ [items]="filterConfiguration.endpoints"
[model]="filterForm.endpoints"
></multi-select-dropdown>
</th>
@@ -377,10 +388,10 @@
<ng-container matColumnDef="shape-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'shapes'"
- [items]="filterConfiguration.shapes"
+ [items]="filterConfiguration.shapes"
[model]="filterForm.shapes"
></multi-select-dropdown>
</th>
@@ -388,10 +399,10 @@
<ng-container matColumnDef="status-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'statuses'"
- [items]="filterConfiguration.statuses"
+ [items]="filterConfiguration.statuses"
[model]="filterForm.statuses"
></multi-select-dropdown>
</th>
@@ -399,10 +410,10 @@
<ng-container matColumnDef="resource-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'resources'"
- [items]="filterConfiguration.resources"
+ [items]="filterConfiguration.resources"
[model]="filterForm.resources"
></multi-select-dropdown>
</th>
@@ -411,22 +422,22 @@
<ng-container matColumnDef="actions-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="actions-col filter-row-item">
<div class="actions">
- <button
- mat-icon-button
- class="btn reset"
- (click)="resetFilterConfigurations()"
+ <button
+ mat-icon-button
+ class="btn reset"
+ (click)="resetFilterConfigurations()"
[disabled]="!isFilterSelected"
>
<i class="material-icons">close</i>
</button>
- <button
- mat-icon-button
- class="btn apply"
+ <button
+ mat-icon-button
+ class="btn apply"
(click)="applyFilter(filterForm)"
[disabled]="isFilterChanged"
>
- <i
+ <i
class="material-icons"
[ngClass]="{'not-allowed': allFilteredEnvironmentData?.length == 0 && !filtering}"
>
@@ -439,7 +450,7 @@
<ng-container matColumnDef="placeholder">
<td mat-footer-cell *matFooterCellDef colspan="8" class="no-border">
- <div
+ <div
class="info"
*ngIf="(!allFilteredEnvironmentData) && !filtering || (allFilteredEnvironmentData?.length == 0) && !filtering"
>
@@ -450,36 +461,36 @@
</ng-container>
<ng-container matColumnDef="scrollButtons">
- <td
- mat-footer-cell
- *matFooterCellDef
- colspan="9"
+ <td
+ mat-footer-cell
+ *matFooterCellDef
+ colspan="9"
class="buttons-wrap"
></td>
</ng-container>
- <tr
- mat-header-row
- *matHeaderRowDef="displayedColumns; sticky: true"
+ <tr
+ mat-header-row
+ *matHeaderRowDef="displayedColumns; sticky: true"
class="header-row"
></tr>
- <tr
- [hidden]="!collapsedFilterRow"
- mat-header-row
+ <tr
+ [hidden]="!collapsedFilterRow"
+ mat-header-row
*matHeaderRowDef="displayedFilterColumns; sticky: true"
class="filter-row"
></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
- <tr
- [hidden]="allFilteredEnvironmentData?.length"
- mat-footer-row *matFooterRowDef="['placeholder']"
+ <tr
+ [hidden]="allFilteredEnvironmentData?.length"
+ mat-footer-row *matFooterRowDef="['placeholder']"
class="info"
></tr>
- <tr
- [hidden]="!tableEl || !tableEl['offsetWidth'] || tableWrapper.offsetWidth - tableEl['offsetWidth'] > -16 || !allFilteredEnvironmentData?.length"
- mat-footer-row
- *matFooterRowDef="['scrollButtons']; sticky: true"
+ <tr
+ [hidden]="!tableEl || !tableEl['offsetWidth'] || tableWrapper.offsetWidth - tableEl['offsetWidth'] > -16 || !allFilteredEnvironmentData?.length"
+ mat-footer-row
+ *matFooterRowDef="['scrollButtons']; sticky: true"
class="info"
></tr>
</table>
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
index a122af1c6..d757eedac 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
@@ -142,7 +142,7 @@ export class ManagementGridComponent implements OnInit, AfterViewInit, AfterView
this.applyFilter(this.cashedFilterForm || this.filterForm);
}
this.progressBarService.stopProgressBar();
- },
+ },
() => {
this.progressBarService.stopProgressBar();
}
@@ -186,8 +186,8 @@ export class ManagementGridComponent implements OnInit, AfterViewInit, AfterView
const containsStatus = (list, selectedItems) => {
if (list) {
- return list.filter((item: any) => {
- if (selectedItems.indexOf(item.status) !== -1) return item;
+ return list.filter((item: any) => {
+ if (selectedItems.indexOf(item.status) !== -1) return item;
});
}
};
@@ -196,30 +196,30 @@ export class ManagementGridComponent implements OnInit, AfterViewInit, AfterView
if (config) {
filteredData = filteredData.filter(item => {
const isUser = config.users.length > 0 ? (config.users.indexOf(item.user) !== -1) : true;
- const isTypeName = item.name
- ? item.name.toLowerCase().indexOf(config.type.toLowerCase()) !== -1
+ const isTypeName = item.name
+ ? item.name.toLowerCase().indexOf(config.type.toLowerCase()) !== -1
: item.type.toLowerCase().indexOf(config.type.toLowerCase()) !== -1;
- const isStatus = config.statuses.length > 0
- ? (config.statuses.indexOf(item.status) !== -1)
+ const isStatus = config.statuses.length > 0
+ ? (config.statuses.indexOf(item.status) !== -1)
: (config.type !== 'active');
- const isShape = config.shapes.length > 0
+ const isShape = config.shapes.length > 0
? (config.shapes.indexOf(item.shape) !== -1 ||
config.shapes.indexOf(item.gpu_type) !== -1 ||
- config.shapes.indexOf(`GPU count: ${item.gpu_count}`) !== -1)
+ config.shapes.indexOf(`GPU count: ${item.gpu_count}`) !== -1)
: true;
- const isProject = config.projects.length > 0
- ? (config.projects.indexOf(item.project) !== -1)
+ const isProject = config.projects.length > 0
+ ? (config.projects.indexOf(item.project) !== -1)
: true;
- const isEndpoint = config.endpoints.length > 0
- ? (config.endpoints.indexOf(item.endpoint) !== -1)
+ const isEndpoint = config.endpoints.length > 0
+ ? (config.endpoints.indexOf(item.endpoint) !== -1)
: true;
const modifiedResources = containsStatus(item.resources, config.resources);
- let isResources = config.resources.length > 0
- ? (modifiedResources && modifiedResources.length > 0)
+ let isResources = config.resources.length > 0
+ ? (modifiedResources && modifiedResources.length > 0)
: true;
- if (config.resources.length > 0 && modifiedResources && modifiedResources.length > 0) {
- item.resources = modifiedResources;
+ if (config.resources.length > 0 && modifiedResources && modifiedResources.length > 0) {
+ item.resources = modifiedResources;
}
if (config.resources && config.resources.length === 0 && config.type === 'active' ||
@@ -288,7 +288,13 @@ export class ManagementGridComponent implements OnInit, AfterViewInit, AfterView
}
});
- this.filterConfiguration = new ManagementConfigModel(users, '', projects, [...shapes, ...gpuTypes, ...gpuCounts], statuses, resources, endpoints);
+ this.filterConfiguration = new ManagementConfigModel(
+ users,
+ '',
+ projects,
+ [...shapes, ...gpuTypes, ...gpuCounts],
+ statuses, resources, endpoints
+ );
}
public openNotebookDetails(data) {
@@ -352,7 +358,10 @@ export class ManagementGridComponent implements OnInit, AfterViewInit, AfterView
selector: 'confirm-dialog',
template: `
<div class="dialog-header">
- <h4 class="modal-title"><span class="capitalize">{{ data.action }}</span> resource</h4>
+ <h4 class="modal-title">
+ <span class="capitalize">{{ data.action }}</span>
+ <span *ngIf="data.action !== 'create image'"> resource</span>
+ </h4>
<button type="button" class="close" (click)="dialogRef.close()">×</button>
</div>
<div mat-dialog-content class="content">
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
index d6c414c58..f7d3179d0 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
@@ -29,7 +29,7 @@ import {
StorageService
} from '../../core/services';
-import { ActionsType, EnvironmentModel, GeneralEnvironmentStatus, ModalData, ModalDataType } from './management.model';
+import {ActionsType, ActionTypeOptions, EnvironmentModel, GeneralEnvironmentStatus, ModalData, ModalDataType} from './management.model';
import { HTTP_STATUS_CODES } from '../../core/util';
import { BackupDilogComponent } from './backup-dilog/backup-dilog.component';
import { SsnMonitorComponent } from './ssn-monitor/ssn-monitor.component';
@@ -43,6 +43,7 @@ import { ConfirmationDialogComponent, ConfirmationDialogType } from '../../share
import { ManagementGridComponent, ReconfirmationDialogComponent } from './management-grid/management-grid.component';
import { FolderTreeComponent } from '../../resources/bucket-browser/folder-tree/folder-tree.component';
import { StatusTypes } from '../../core/models';
+import {AmiCreateDialogComponent} from '../../resources/exploratory/ami-create-dialog';
@Component({
selector: 'environments-management',
@@ -225,8 +226,7 @@ export class ManagementComponent implements OnInit {
this.isActionsOpen = !this.isActionsOpen;
}
- toggleResourceAction($event): void {
- const { environment, action, resource } = $event;
+ toggleResourceAction({ environment, action, resource = null}): void {
this.openDialog(environment, action, resource);
}
@@ -239,7 +239,7 @@ export class ManagementComponent implements OnInit {
}
}
- public resourceAction(action) {
+ public resourceAction(action: ActionTypeOptions) {
this.toggleResourceAction({ environment: this.selected, action: action });
}
@@ -265,7 +265,14 @@ export class ManagementComponent implements OnInit {
observer.next = (res) => {
if (res) {
notebooks.forEach((env) => {
- this.getNotebookAction(env, action);
+ if (action === 'create image') {
+ env['isAdmin'] = true;
+ env['userName'] = env.user;
+ this.dialog.open(AmiCreateDialogComponent, { data: env, panelClass: 'modal-sm' })
+ .afterClosed().subscribe();
+ } else {
+ this.getNotebookAction(env, action);
+ }
});
}
this.clearSelection();
@@ -306,7 +313,7 @@ export class ManagementComponent implements OnInit {
return {...config, notebooks};
}
- private getNotebookAction(env: EnvironmentModel, action: ActionsType) {
+ private getNotebookAction(env: EnvironmentModel, action: ActionsType): void {
this.manageEnvironmentsService.environmentManagement(env.user, action, env.project, env.name)
.subscribe(
() => this.buildGrid(),
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
index 56ce00ff7..5e7435302 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
@@ -117,10 +117,10 @@ export class ManagementConfigModel {
export interface ModalData {
action: ActionsType;
- resource_name?: any;
- user?: any,
+ resource_name?: any;
+ user?: any;
type: string;
- notebooks?: any
+ notebooks?: any;
}
export enum ModalDataType {
@@ -133,5 +133,8 @@ export enum ActionsType {
terminate = 'terminate',
start = 'start',
run = 'run',
- recreate = 'recreate'
-}
\ No newline at end of file
+ recreate = 'recreate',
+ createImage = 'create image'
+}
+
+export type ActionTypeOptions = 'stop' | 'terminate' | 'start' | 'run' | 'recreate' | 'createAmi';
diff --git a/services/self-service/src/main/resources/webapp/src/app/core/pipes/convert-action-type-pipe/convert-action-type.pipe.ts b/services/self-service/src/main/resources/webapp/src/app/core/pipes/convert-action-type-pipe/convert-action-type.pipe.ts
index e1459fcf3..1c47afc10 100644
--- a/services/self-service/src/main/resources/webapp/src/app/core/pipes/convert-action-type-pipe/convert-action-type.pipe.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/core/pipes/convert-action-type-pipe/convert-action-type.pipe.ts
@@ -22,27 +22,31 @@ import { ActionsType } from '../../../administration/management/management.model
const actionTypes = {
stopped: 'Stopped',
- terminated: ' Terminated',
- started: 'Started'
-}
+ terminated: 'Terminated',
+ started: 'Starting',
+ creating: 'Creating Image',
+ unknown: 'Unknown type'
+};
@Pipe({ name: 'convertactiontype' })
export class ConvertActionTypePipe implements PipeTransform {
- transform(value: string,): string {
- if(value === ActionsType.stop) {
- return actionTypes.stopped
+ transform(value: string): string {
+ if (value === ActionsType.stop) {
+ return actionTypes.stopped;
}
- if(value === ActionsType.start) {
- return actionTypes.started
+ if (value === ActionsType.start) {
+ return actionTypes.started;
}
- if(value === ActionsType.terminate) {
- return actionTypes.terminated
+ if (value === ActionsType.terminate) {
+ return actionTypes.terminated;
}
- else {
- return 'Unknown type'
+ if (value === ActionsType.createImage) {
+ return actionTypes.creating;
+ } else {
+ return actionTypes.unknown;
}
}
}
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html
index ae576f2d9..a5befe290 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html
@@ -45,19 +45,19 @@
</div>
</form>
<div class="text-center m-top-30 m-bott-10">
- <button
- mat-raised-button
- type="button"
- class="butt action"
+ <button
+ mat-raised-button
+ type="button"
+ class="butt action"
(click)="dialogRef.close()"
>
Cancel
</button>
- <button
- mat-raised-button
- type="button"
+ <button
+ mat-raised-button
+ type="button"
[disabled]="!createAMIForm.valid"
- (click)="assignChanges(createAMIForm.value)"
+ (click)="assignChanges(createAMIForm.value)"
class="butt butt-success action"
>
Create
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts
index 315f8f3c6..455468a28 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts
@@ -22,7 +22,7 @@ import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { ToastrService } from 'ngx-toastr';
-import { UserResourceService } from '../../../core/services';
+import {ManageEnvironmentsService, UserResourceService} from '../../../core/services';
import { HTTP_STATUS_CODES, PATTERNS } from '../../../core/util';
import { DICTIONARY } from '../../../../dictionary/global.dictionary';
@@ -38,6 +38,7 @@ export class AmiCreateDialogComponent implements OnInit {
public provider: string;
delimitersRegex = /[-_]?/g;
imagesList: any;
+ private isAdmin: boolean = false;
constructor(
@Inject(MAT_DIALOG_DATA) public data: any,
@@ -45,28 +46,43 @@ export class AmiCreateDialogComponent implements OnInit {
public dialogRef: MatDialogRef<AmiCreateDialogComponent>,
private _userResource: UserResourceService,
private _fb: FormBuilder,
+ private manageEnvironmentsService: ManageEnvironmentsService,
) { }
ngOnInit() {
this.notebook = this.data;
this.provider = this.data.cloud_provider;
+ this.checkRole();
this.initFormModel();
this._userResource.getImagesList(this.data.project).subscribe(res => this.imagesList = res);
}
- public assignChanges(data) {
- this._userResource.createAMI(data).subscribe(
- response => response.status === HTTP_STATUS_CODES.ACCEPTED && this.dialogRef.close(true),
- error => this.toastr.error(error.message || `Image creation failed!`, 'Oops!'));
+ public assignChanges(data): void {
+ if (this.isAdmin) {
+ const { exploratory_name, project_name, name, description } = data;
+ const imageInfo = { user: this.data.userName, imageName: name, description, project_name, exploratory_name};
+ this.manageEnvironmentsService.environmentManagement(imageInfo, 'createImage', project_name, exploratory_name).subscribe(
+ () => { this.dialogRef.close(true); });
+ } else {
+ this._userResource.createAMI(data).subscribe(
+ response => response.status === HTTP_STATUS_CODES.ACCEPTED && this.dialogRef.close(true),
+ error => this.toastr.error(error.message || `Image creation failed!`, 'Oops!'));
+ }
+ }
+
+ private checkRole(): void {
+ if (this.data?.isAdmin) {
+ this.isAdmin = this.data.isAdmin;
+ }
}
private initFormModel(): void {
this.createAMIForm = this._fb.group({
name: ['', [
- Validators.required,
- Validators.pattern(PATTERNS.namePattern),
- Validators.maxLength(10),
+ Validators.required,
+ Validators.pattern(PATTERNS.namePattern),
+ Validators.maxLength(10),
this.checkDuplication.bind(this)
]],
description: [''],
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datalab.apache.org
For additional commands, e-mail: commits-help@datalab.apache.org
[incubator-datalab] 09/09: small fix
Posted by dy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
dyankiv pushed a commit to branch DATALAB-2785
in repository https://gitbox.apache.org/repos/asf/incubator-datalab.git
commit 36be6ec7059d020f299dbd7042903fba802f10a3
Author: Denys Yankiv <de...@gmail.com>
AuthorDate: Wed May 18 13:34:30 2022 +0300
small fix
---
.../resources/dto/ExploratoryImageCreateFormAdminDTO.java | 3 ++-
.../datalab/backendapi/service/impl/EnvironmentServiceImpl.java | 6 +++---
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryImageCreateFormAdminDTO.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryImageCreateFormAdminDTO.java
index 69498d362..9c8b545b7 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryImageCreateFormAdminDTO.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryImageCreateFormAdminDTO.java
@@ -11,7 +11,8 @@ public class ExploratoryImageCreateFormAdminDTO {
@NotBlank
private String user;
@NotBlank
- private final String name;
+ @JsonProperty("imageName")
+ private String name;
@NotBlank
@JsonProperty("exploratory_name")
private String notebookName;
diff --git a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/EnvironmentServiceImpl.java b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/EnvironmentServiceImpl.java
index 7c9ebfc29..99aa23bac 100644
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/EnvironmentServiceImpl.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/service/impl/EnvironmentServiceImpl.java
@@ -111,14 +111,14 @@ public class EnvironmentServiceImpl implements EnvironmentService {
@ProjectAdmin
@Override
- public void createImage(@User UserInfo userInfo, String user, String project, String exploratoryName, String imageName, String description) {
- imageExploratoryService.createImage(securityService.getUserInfoOffline(user), project,exploratoryName, imageName, description, null);
+ public void createImage(@User UserInfo userInfo, String user, @Project String project, String exploratoryName, String imageName, String description) {
+ imageExploratoryService.createImage(securityService.getUserInfoOffline(user), project, exploratoryName, imageName, description, null);
}
@ProjectAdmin
@Override
public void startExploratory(@User UserInfo userInfo, String user, @Project String project, String exploratoryName) {
- exploratoryService.start(securityService.getServiceAccountInfo(user),exploratoryName,project,null);
+ exploratoryService.start(securityService.getServiceAccountInfo(user), exploratoryName, project, null);
}
@Override
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datalab.apache.org
For additional commands, e-mail: commits-help@datalab.apache.org
[incubator-datalab] 08/09: Merge remote-tracking branch 'origin/feat/DATALAB-2771/add-create-image-btn-for-admin' into DATALAB-2785
Posted by dy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
dyankiv pushed a commit to branch DATALAB-2785
in repository https://gitbox.apache.org/repos/asf/incubator-datalab.git
commit 9b44f4238b073d039368de29d35606192580040d
Merge: 01496306b 3f9df815d
Author: Denys Yankiv <de...@gmail.com>
AuthorDate: Tue May 17 09:49:19 2022 +0300
Merge remote-tracking branch 'origin/feat/DATALAB-2771/add-create-image-btn-for-admin' into DATALAB-2785
.../webapp/src/app/core/services/applicationServiceFacade.service.ts | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datalab.apache.org
For additional commands, e-mail: commits-help@datalab.apache.org
[incubator-datalab] 01/09: added create ami button
Posted by dy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
dyankiv pushed a commit to branch DATALAB-2785
in repository https://gitbox.apache.org/repos/asf/incubator-datalab.git
commit acf9d94e8134b42d4c2677dc27b179eb554390be
Author: Hennadii_Shpak <bo...@gmail.com>
AuthorDate: Tue May 3 18:18:27 2022 +0300
added create ami button
---
.../management-grid/management-grid.component.html | 221 +++++++++++----------
.../management-grid/management-grid.component.ts | 42 ++--
.../management/management.component.ts | 19 +-
.../administration/management/management.model.ts | 13 +-
.../ami-create-dialog.component.html | 16 +-
.../ami-create-dialog.component.ts | 32 ++-
6 files changed, 193 insertions(+), 150 deletions(-)
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
index c8c793d8c..e280017f4 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.html
@@ -18,14 +18,14 @@
-->
<div class="managment-wrapper scrolling" #pageWrapper (scroll)="scrollTable($event)" (resize)="onResize($event)">
<div class="ani scrolling scroll-wrapper" #wrapper (scroll)="scrollTable($event)">
- <div
- class="nav-buttons"
+ <div
+ class="nav-buttons"
[ngStyle]="{'width.px': userAgentIndex === -1 ? tableWrapperWidth - 3 : tableWrapperWidth - 7 }"
- [ngClass]="{'border': tableEl['offsetHeight'] < tableWrapper.offsetHeight - 48}"
+ [ngClass]="{'border': tableEl['offsetHeight'] < tableWrapper.offsetHeight - 48}"
[hidden]="!(tableWrapper.offsetWidth - tableEl['offsetWidth'] < 0)"
>
<div class="button-container">
- <button
+ <button
mat-mini-fab aria-label="Scroll left"
(click)="sctollTo('left')"
[ngClass]="{'not-allowed': wrapper.scrollLeft === 0 }"
@@ -34,7 +34,7 @@
</button>
</div>
<div class="button-container" [ngClass]="{'not-allowed': checkMaxRight()}">
- <button
+ <button
mat-mini-fab aria-label="Scroll right"
(click)="sctollTo('right')"
[ngClass]="{'not-allowed': !(isMaxRight | async)}"
@@ -61,10 +61,10 @@
</button>
</th>
<td mat-cell *matCellDef="let element">
- <ng-template
- [ngIf]="element.type !== 'odahu'
- && element.type !== 'edge node'
- && (element.status==='running' || element.status==='stopped')
+ <ng-template
+ [ngIf]="element.type !== 'odahu'
+ && element.type !== 'edge node'
+ && (element.status==='running' || element.status==='stopped')
&& !clustersInProgress(element.resources)"
>
<datalab-checkbox
@@ -79,10 +79,10 @@
<ng-container matColumnDef="user">
<th mat-header-cell *matHeaderCellDef class="user label-header">
<span class="label">User</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -105,17 +105,17 @@
<ng-container matColumnDef="project">
<th mat-header-cell *matHeaderCellDef class="project label-header">
<span class="label">Project</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
<span *ngIf="filtering && filterForm.projects.length > 0 && !collapsedFilterRow">filter_list</span>
<span [hidden]="filtering && filterForm.projects.length > 0 && !collapsedFilterRow">more_vert</span>
</i>
- </button>
+ </button>
</th>
<td mat-cell *matCellDef="let element">{{ element.project }}</td>
</ng-container>
@@ -123,10 +123,10 @@
<ng-container matColumnDef="endpoint">
<th mat-header-cell *matHeaderCellDef class="endpoint label-header">
<span class="label">Endpoint</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -141,10 +141,10 @@
<ng-container matColumnDef="type">
<th mat-header-cell *matHeaderCellDef class="type label-header">
<span class="label">Name</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -168,10 +168,10 @@
<ng-container matColumnDef="shape">
<th mat-header-cell *matHeaderCellDef class="shape label-header">
<span class="label">Shape / Resource id</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -190,10 +190,10 @@
<ng-container matColumnDef="status">
<th mat-header-cell *matHeaderCellDef class="status label-header">
<span class="label">Status</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -210,10 +210,10 @@
<ng-container matColumnDef="resources">
<th mat-header-cell *matHeaderCellDef class="resources label-header">
<span class="label">Compute</span>
- <button
- mat-icon-button
- aria-label="More"
- class="ar"
+ <button
+ mat-icon-button
+ aria-label="More"
+ class="ar"
(click)="toggleFilterRow()"
>
<i class="material-icons">
@@ -236,8 +236,8 @@
<div class="resource-actions">
<span class="not-allow">
<a class="start-stop-action" *ngIf="resource.image === 'docker.datalab-dataengine'">
- <i
- class="material-icons"
+ <i
+ class="material-icons"
(click)="toggleResourceAction(element, 'stop', resource)"
[ngClass]="{'not-allowed' : resource.status !== 'running' || selected?.length }"
>
@@ -246,8 +246,8 @@
</a>
</span>
<span class="not-allow">
- <a
- class="remove_butt"
+ <a
+ class="remove_butt"
(click)="toggleResourceAction(element, 'terminate', resource)"
[ngClass]="{ 'disabled' : element.status !== 'running' || (resource.status !== 'running' && resource.status !== 'stopped') || selected?.length }"
>
@@ -267,10 +267,10 @@
</th>
<td mat-cell *matCellDef="let element" class="settings actions-col">
<span [ngClass]="{'not-allow' : selected?.length}">
- <span
- #settings
- class="actions"
- (click)="actions.toggle($event, settings)"
+ <span
+ #settings
+ class="actions"
+ (click)="actions.toggle($event, settings)"
*ngIf="element.type !== 'edge node' && element.type !== 'odahu'"
[ngClass]="{
'disabled' : (element.status !== 'running' && element.status !== 'stopped')
@@ -281,39 +281,50 @@
<bubble-up #actions class="list-menu" position="bottom-left" alternative="top-left">
<ul class="list-unstyled">
<li
- matTooltip="{{ element.type !== 'edge node'
- ? 'Unable to stop notebook because at least one computational resource is in progress'
+ matTooltip="{{ element.type !== 'edge node'
+ ? 'Unable to stop notebook because at least one computational resource is in progress'
: 'Unable to stop edge node because at least one resource of this user is in progress' }}"
- matTooltipPosition="above"
+ matTooltipPosition="above"
[matTooltipDisabled]="!isResourcesInProgress(element)"
[hidden]="element.name === 'edge node' && element.status === 'stopped'"
>
- <div
+ <div
(click)="toggleResourceAction(element, 'stop')"
- [ngClass]="{'not-allowed' : element.status === 'stopped' || element.status === 'stopping' ||
- element.status === 'starting' || element.status === 'creating image' ||
+ [ngClass]="{'not-allowed' : element.status === 'stopped' || element.status === 'stopping' ||
+ element.status === 'starting' || element.status === 'creating image' ||
element.status === 'failed' || isResourcesInProgress(element)}"
>
<i class="material-icons">pause_circle_outline</i>
<span>Stop</span>
</div>
</li>
- <li
+ <li
*ngIf="element.name !== 'edge node'"
matTooltip="Unable to terminate notebook because at least one compute is in progress"
- matTooltipPosition="above"
+ matTooltipPosition="above"
[matTooltipDisabled]="!isResourcesInProgress(element)"
>
- <div
+ <div
(click)="toggleResourceAction(element, 'terminate')"
- [ngClass]="{'not-allowed' : element.status !== 'running' &&
- element.status !== 'stopped' ||
+ [ngClass]="{'not-allowed' : element.status !== 'running' &&
+ element.status !== 'stopped' ||
isResourcesInProgress(element)}"
>
<i class="material-icons">phonelink_off</i>
<span>Terminate</span>
</div>
</li>
+ <li
+ *ngIf="element.status !== 'terminated' && element.image !== 'docker.datalab-superset'
+ && element.image !== 'docker.datalab-jupyterlab'"
+ >
+ <div
+ (click)="toggleResourceAction(element, 'Create Image')"
+ >
+ <i class="material-icons">view_module</i>
+ <span>Create AMI</span>
+ </div>
+ </li>
<li *ngIf="element.status === 'stopped'">
<div (click)="toggleResourceAction(element, 'start')">
<i class="material-icons">play_circle_outline</i>
@@ -333,9 +344,9 @@
<ng-container matColumnDef="user-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
- [type]="'users'"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
+ [type]="'users'"
[items]="filterConfiguration.users"
[model]="filterForm.users"
></multi-select-dropdown>
@@ -344,11 +355,11 @@
<ng-container matColumnDef="type-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <input
- placeholder="Filter by name"
- type="text"
+ <input
+ placeholder="Filter by name"
+ type="text"
class="form-control filter-field"
- [value]="filterForm.type"
+ [value]="filterForm.type"
(input)="onFilterNameUpdate($event.target['value'])"
/>
</th>
@@ -356,20 +367,20 @@
<ng-container matColumnDef="project-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'projects'"
- [items]="filterConfiguration.projects"
+ [items]="filterConfiguration.projects"
[model]="filterForm.projects"
></multi-select-dropdown>
</th>
</ng-container>
<ng-container matColumnDef="endpoint-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'endpoints'"
- [items]="filterConfiguration.endpoints"
+ [items]="filterConfiguration.endpoints"
[model]="filterForm.endpoints"
></multi-select-dropdown>
</th>
@@ -377,10 +388,10 @@
<ng-container matColumnDef="shape-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'shapes'"
- [items]="filterConfiguration.shapes"
+ [items]="filterConfiguration.shapes"
[model]="filterForm.shapes"
></multi-select-dropdown>
</th>
@@ -388,10 +399,10 @@
<ng-container matColumnDef="status-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'statuses'"
- [items]="filterConfiguration.statuses"
+ [items]="filterConfiguration.statuses"
[model]="filterForm.statuses"
></multi-select-dropdown>
</th>
@@ -399,10 +410,10 @@
<ng-container matColumnDef="resource-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="filter-row-item">
- <multi-select-dropdown
- (selectionChange)="onUpdate($event)"
+ <multi-select-dropdown
+ (selectionChange)="onUpdate($event)"
[type]="'resources'"
- [items]="filterConfiguration.resources"
+ [items]="filterConfiguration.resources"
[model]="filterForm.resources"
></multi-select-dropdown>
</th>
@@ -411,22 +422,22 @@
<ng-container matColumnDef="actions-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="actions-col filter-row-item">
<div class="actions">
- <button
- mat-icon-button
- class="btn reset"
- (click)="resetFilterConfigurations()"
+ <button
+ mat-icon-button
+ class="btn reset"
+ (click)="resetFilterConfigurations()"
[disabled]="!isFilterSelected"
>
<i class="material-icons">close</i>
</button>
- <button
- mat-icon-button
- class="btn apply"
+ <button
+ mat-icon-button
+ class="btn apply"
(click)="applyFilter(filterForm)"
[disabled]="isFilterChanged"
>
- <i
+ <i
class="material-icons"
[ngClass]="{'not-allowed': allFilteredEnvironmentData?.length == 0 && !filtering}"
>
@@ -439,7 +450,7 @@
<ng-container matColumnDef="placeholder">
<td mat-footer-cell *matFooterCellDef colspan="8" class="no-border">
- <div
+ <div
class="info"
*ngIf="(!allFilteredEnvironmentData) && !filtering || (allFilteredEnvironmentData?.length == 0) && !filtering"
>
@@ -450,36 +461,36 @@
</ng-container>
<ng-container matColumnDef="scrollButtons">
- <td
- mat-footer-cell
- *matFooterCellDef
- colspan="9"
+ <td
+ mat-footer-cell
+ *matFooterCellDef
+ colspan="9"
class="buttons-wrap"
></td>
</ng-container>
- <tr
- mat-header-row
- *matHeaderRowDef="displayedColumns; sticky: true"
+ <tr
+ mat-header-row
+ *matHeaderRowDef="displayedColumns; sticky: true"
class="header-row"
></tr>
- <tr
- [hidden]="!collapsedFilterRow"
- mat-header-row
+ <tr
+ [hidden]="!collapsedFilterRow"
+ mat-header-row
*matHeaderRowDef="displayedFilterColumns; sticky: true"
class="filter-row"
></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
- <tr
- [hidden]="allFilteredEnvironmentData?.length"
- mat-footer-row *matFooterRowDef="['placeholder']"
+ <tr
+ [hidden]="allFilteredEnvironmentData?.length"
+ mat-footer-row *matFooterRowDef="['placeholder']"
class="info"
></tr>
- <tr
- [hidden]="!tableEl || !tableEl['offsetWidth'] || tableWrapper.offsetWidth - tableEl['offsetWidth'] > -16 || !allFilteredEnvironmentData?.length"
- mat-footer-row
- *matFooterRowDef="['scrollButtons']; sticky: true"
+ <tr
+ [hidden]="!tableEl || !tableEl['offsetWidth'] || tableWrapper.offsetWidth - tableEl['offsetWidth'] > -16 || !allFilteredEnvironmentData?.length"
+ mat-footer-row
+ *matFooterRowDef="['scrollButtons']; sticky: true"
class="info"
></tr>
</table>
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
index a122af1c6..e3342b5e0 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management-grid/management-grid.component.ts
@@ -142,7 +142,7 @@ export class ManagementGridComponent implements OnInit, AfterViewInit, AfterView
this.applyFilter(this.cashedFilterForm || this.filterForm);
}
this.progressBarService.stopProgressBar();
- },
+ },
() => {
this.progressBarService.stopProgressBar();
}
@@ -186,8 +186,8 @@ export class ManagementGridComponent implements OnInit, AfterViewInit, AfterView
const containsStatus = (list, selectedItems) => {
if (list) {
- return list.filter((item: any) => {
- if (selectedItems.indexOf(item.status) !== -1) return item;
+ return list.filter((item: any) => {
+ if (selectedItems.indexOf(item.status) !== -1) return item;
});
}
};
@@ -196,30 +196,30 @@ export class ManagementGridComponent implements OnInit, AfterViewInit, AfterView
if (config) {
filteredData = filteredData.filter(item => {
const isUser = config.users.length > 0 ? (config.users.indexOf(item.user) !== -1) : true;
- const isTypeName = item.name
- ? item.name.toLowerCase().indexOf(config.type.toLowerCase()) !== -1
+ const isTypeName = item.name
+ ? item.name.toLowerCase().indexOf(config.type.toLowerCase()) !== -1
: item.type.toLowerCase().indexOf(config.type.toLowerCase()) !== -1;
- const isStatus = config.statuses.length > 0
- ? (config.statuses.indexOf(item.status) !== -1)
+ const isStatus = config.statuses.length > 0
+ ? (config.statuses.indexOf(item.status) !== -1)
: (config.type !== 'active');
- const isShape = config.shapes.length > 0
+ const isShape = config.shapes.length > 0
? (config.shapes.indexOf(item.shape) !== -1 ||
config.shapes.indexOf(item.gpu_type) !== -1 ||
- config.shapes.indexOf(`GPU count: ${item.gpu_count}`) !== -1)
+ config.shapes.indexOf(`GPU count: ${item.gpu_count}`) !== -1)
: true;
- const isProject = config.projects.length > 0
- ? (config.projects.indexOf(item.project) !== -1)
+ const isProject = config.projects.length > 0
+ ? (config.projects.indexOf(item.project) !== -1)
: true;
- const isEndpoint = config.endpoints.length > 0
- ? (config.endpoints.indexOf(item.endpoint) !== -1)
+ const isEndpoint = config.endpoints.length > 0
+ ? (config.endpoints.indexOf(item.endpoint) !== -1)
: true;
const modifiedResources = containsStatus(item.resources, config.resources);
- let isResources = config.resources.length > 0
- ? (modifiedResources && modifiedResources.length > 0)
+ let isResources = config.resources.length > 0
+ ? (modifiedResources && modifiedResources.length > 0)
: true;
- if (config.resources.length > 0 && modifiedResources && modifiedResources.length > 0) {
- item.resources = modifiedResources;
+ if (config.resources.length > 0 && modifiedResources && modifiedResources.length > 0) {
+ item.resources = modifiedResources;
}
if (config.resources && config.resources.length === 0 && config.type === 'active' ||
@@ -288,7 +288,13 @@ export class ManagementGridComponent implements OnInit, AfterViewInit, AfterView
}
});
- this.filterConfiguration = new ManagementConfigModel(users, '', projects, [...shapes, ...gpuTypes, ...gpuCounts], statuses, resources, endpoints);
+ this.filterConfiguration = new ManagementConfigModel(
+ users,
+ '',
+ projects,
+ [...shapes, ...gpuTypes, ...gpuCounts],
+ statuses, resources, endpoints
+ );
}
public openNotebookDetails(data) {
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
index d6c414c58..4dd9de2ac 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.component.ts
@@ -29,7 +29,7 @@ import {
StorageService
} from '../../core/services';
-import { ActionsType, EnvironmentModel, GeneralEnvironmentStatus, ModalData, ModalDataType } from './management.model';
+import {ActionsType, ActionTypeOptions, EnvironmentModel, GeneralEnvironmentStatus, ModalData, ModalDataType} from './management.model';
import { HTTP_STATUS_CODES } from '../../core/util';
import { BackupDilogComponent } from './backup-dilog/backup-dilog.component';
import { SsnMonitorComponent } from './ssn-monitor/ssn-monitor.component';
@@ -43,6 +43,7 @@ import { ConfirmationDialogComponent, ConfirmationDialogType } from '../../share
import { ManagementGridComponent, ReconfirmationDialogComponent } from './management-grid/management-grid.component';
import { FolderTreeComponent } from '../../resources/bucket-browser/folder-tree/folder-tree.component';
import { StatusTypes } from '../../core/models';
+import {AmiCreateDialogComponent} from '../../resources/exploratory/ami-create-dialog';
@Component({
selector: 'environments-management',
@@ -225,8 +226,7 @@ export class ManagementComponent implements OnInit {
this.isActionsOpen = !this.isActionsOpen;
}
- toggleResourceAction($event): void {
- const { environment, action, resource } = $event;
+ toggleResourceAction({ environment, action, resource = null}): void {
this.openDialog(environment, action, resource);
}
@@ -239,7 +239,7 @@ export class ManagementComponent implements OnInit {
}
}
- public resourceAction(action) {
+ public resourceAction(action: ActionTypeOptions) {
this.toggleResourceAction({ environment: this.selected, action: action });
}
@@ -265,7 +265,14 @@ export class ManagementComponent implements OnInit {
observer.next = (res) => {
if (res) {
notebooks.forEach((env) => {
- this.getNotebookAction(env, action);
+ if (action === 'Create Image') {
+ env['isAdmin'] = true;
+ env['userName'] = env.user;
+ this.dialog.open(AmiCreateDialogComponent, { data: env, panelClass: 'modal-sm' })
+ .afterClosed().subscribe();
+ } else {
+ this.getNotebookAction(env, action);
+ }
});
}
this.clearSelection();
@@ -306,7 +313,7 @@ export class ManagementComponent implements OnInit {
return {...config, notebooks};
}
- private getNotebookAction(env: EnvironmentModel, action: ActionsType) {
+ private getNotebookAction(env: EnvironmentModel, action: ActionsType): void {
this.manageEnvironmentsService.environmentManagement(env.user, action, env.project, env.name)
.subscribe(
() => this.buildGrid(),
diff --git a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
index 56ce00ff7..b57e7b670 100644
--- a/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/administration/management/management.model.ts
@@ -117,10 +117,10 @@ export class ManagementConfigModel {
export interface ModalData {
action: ActionsType;
- resource_name?: any;
- user?: any,
+ resource_name?: any;
+ user?: any;
type: string;
- notebooks?: any
+ notebooks?: any;
}
export enum ModalDataType {
@@ -133,5 +133,8 @@ export enum ActionsType {
terminate = 'terminate',
start = 'start',
run = 'run',
- recreate = 'recreate'
-}
\ No newline at end of file
+ recreate = 'recreate',
+ createAmi = 'createAmi'
+}
+
+export type ActionTypeOptions = 'stop' | 'terminate' | 'start' | 'run' | 'recreate' | 'createAmi';
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html
index ae576f2d9..a5befe290 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.html
@@ -45,19 +45,19 @@
</div>
</form>
<div class="text-center m-top-30 m-bott-10">
- <button
- mat-raised-button
- type="button"
- class="butt action"
+ <button
+ mat-raised-button
+ type="button"
+ class="butt action"
(click)="dialogRef.close()"
>
Cancel
</button>
- <button
- mat-raised-button
- type="button"
+ <button
+ mat-raised-button
+ type="button"
[disabled]="!createAMIForm.valid"
- (click)="assignChanges(createAMIForm.value)"
+ (click)="assignChanges(createAMIForm.value)"
class="butt butt-success action"
>
Create
diff --git a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts
index 315f8f3c6..c5caebc00 100644
--- a/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts
+++ b/services/self-service/src/main/resources/webapp/src/app/resources/exploratory/ami-create-dialog/ami-create-dialog.component.ts
@@ -22,7 +22,7 @@ import { FormGroup, FormBuilder, Validators } from '@angular/forms';
import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
import { ToastrService } from 'ngx-toastr';
-import { UserResourceService } from '../../../core/services';
+import {ManageEnvironmentsService, UserResourceService} from '../../../core/services';
import { HTTP_STATUS_CODES, PATTERNS } from '../../../core/util';
import { DICTIONARY } from '../../../../dictionary/global.dictionary';
@@ -38,6 +38,7 @@ export class AmiCreateDialogComponent implements OnInit {
public provider: string;
delimitersRegex = /[-_]?/g;
imagesList: any;
+ private isAdmin: boolean = false;
constructor(
@Inject(MAT_DIALOG_DATA) public data: any,
@@ -45,28 +46,43 @@ export class AmiCreateDialogComponent implements OnInit {
public dialogRef: MatDialogRef<AmiCreateDialogComponent>,
private _userResource: UserResourceService,
private _fb: FormBuilder,
+ private manageEnvironmentsService: ManageEnvironmentsService,
) { }
ngOnInit() {
this.notebook = this.data;
this.provider = this.data.cloud_provider;
+ this.checkRole();
this.initFormModel();
this._userResource.getImagesList(this.data.project).subscribe(res => this.imagesList = res);
}
- public assignChanges(data) {
- this._userResource.createAMI(data).subscribe(
- response => response.status === HTTP_STATUS_CODES.ACCEPTED && this.dialogRef.close(true),
- error => this.toastr.error(error.message || `Image creation failed!`, 'Oops!'));
+ public assignChanges(data): void {
+ if (this.isAdmin) {
+ const { exploratory_name, project_name, name, description } = data;
+ const imageInfo = { userName: this.data.userName, imageName: name, description};
+ this.manageEnvironmentsService.environmentManagement(imageInfo, 'createAmi', project_name, exploratory_name).subscribe(
+ () => { this.dialogRef.close(true); });
+ } else {
+ this._userResource.createAMI(data).subscribe(
+ response => response.status === HTTP_STATUS_CODES.ACCEPTED && this.dialogRef.close(true),
+ error => this.toastr.error(error.message || `Image creation failed!`, 'Oops!'));
+ }
+ }
+
+ private checkRole(): void {
+ if (this.data?.isAdmin) {
+ this.isAdmin = this.data.isAdmin;
+ }
}
private initFormModel(): void {
this.createAMIForm = this._fb.group({
name: ['', [
- Validators.required,
- Validators.pattern(PATTERNS.namePattern),
- Validators.maxLength(10),
+ Validators.required,
+ Validators.pattern(PATTERNS.namePattern),
+ Validators.maxLength(10),
this.checkDuplication.bind(this)
]],
description: [''],
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datalab.apache.org
For additional commands, e-mail: commits-help@datalab.apache.org
[incubator-datalab] 07/09: resolve conflict
Posted by dy...@apache.org.
This is an automated email from the ASF dual-hosted git repository.
dyankiv pushed a commit to branch DATALAB-2785
in repository https://gitbox.apache.org/repos/asf/incubator-datalab.git
commit 01496306bb7a574e4d23d50600ad0e7779c3f50e
Merge: e6a9f09a4 ae8007f5d
Author: Denys Yankiv <de...@gmail.com>
AuthorDate: Tue May 17 09:48:55 2022 +0300
resolve conflict
.../src/general/lib/os/debian/notebook_lib.py | 8 ++++----
.../src/general/lib/os/fab.py | 3 +++
.../backendapi/resources/EnvironmentResource.java | 15 +++++++--------
.../dto/ExploratoryImageCreateFormAdminDTO.java | 22 ++++++++++++++++++++++
.../management/management.component.ts | 2 +-
.../ami-create-dialog.component.ts | 4 ++--
6 files changed, 39 insertions(+), 15 deletions(-)
diff --cc services/self-service/src/main/java/com/epam/datalab/backendapi/resources/EnvironmentResource.java
index 2fdfda448,9b984bb40..16fa7addc
--- a/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/EnvironmentResource.java
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/EnvironmentResource.java
@@@ -20,7 -20,6 +20,8 @@@
package com.epam.datalab.backendapi.resources;
import com.epam.datalab.auth.UserInfo;
++import com.epam.datalab.backendapi.resources.dto.ExploratoryImageCreateFormAdminDTO;
+import com.epam.datalab.backendapi.resources.dto.ExploratoryImageCreateFormDTO;
import com.epam.datalab.backendapi.service.EnvironmentService;
import com.google.inject.Inject;
import io.dropwizard.auth.Auth;
@@@ -124,19 -119,4 +125,17 @@@ public class EnvironmentResource
environmentService.terminateComputational(userInfo, user, projectName, exploratoryName, computationalName);
return Response.ok().build();
}
+
+ @POST
- @Consumes(MediaType.TEXT_PLAIN)
++ @Consumes(MediaType.APPLICATION_JSON)
+ @Produces(MediaType.APPLICATION_JSON)
+ @Path("createImage/{projectName}/{exploratoryName}")
- public Response createImage(@Auth UserInfo userInfo, @NotEmpty String user,
- @NotEmpty String imageName,
- @NotEmpty String description,
- @PathParam("projectName") String projectName,
- @PathParam("exploratoryName") String exploratoryName,
++ public Response createImage(@Auth UserInfo userInfo,
++ @Valid @NotNull ExploratoryImageCreateFormAdminDTO form,
+ @Context UriInfo uriInfo) {
- log.info("Admin {} is creating an image of exploratory {} of user {}", userInfo.getName(), exploratoryName, user);
- environmentService.createImage(userInfo, user, projectName, exploratoryName, imageName, description);
++ log.info("Admin {} is creating an image of exploratory {} of user {}", userInfo.getName(), form.getNotebookName(), form.getUser());
++ environmentService.createImage(userInfo, form.getUser(), form.getProjectName(), form.getNotebookName(), form.getName(), form.getDescription());
+ return Response.ok().build();
+ }
++
}
diff --cc services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryImageCreateFormAdminDTO.java
index 000000000,000000000..69498d362
new file mode 100644
--- /dev/null
+++ b/services/self-service/src/main/java/com/epam/datalab/backendapi/resources/dto/ExploratoryImageCreateFormAdminDTO.java
@@@ -1,0 -1,0 +1,22 @@@
++package com.epam.datalab.backendapi.resources.dto;
++
++import com.fasterxml.jackson.annotation.JsonProperty;
++import lombok.Data;
++import lombok.ToString;
++import org.hibernate.validator.constraints.NotBlank;
++
++@Data
++@ToString
++public class ExploratoryImageCreateFormAdminDTO {
++ @NotBlank
++ private String user;
++ @NotBlank
++ private final String name;
++ @NotBlank
++ @JsonProperty("exploratory_name")
++ private String notebookName;
++ @NotBlank
++ @JsonProperty("project_name")
++ private String projectName;
++ private final String description;
++}
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@datalab.apache.org
For additional commands, e-mail: commits-help@datalab.apache.org