blob: 6fd6caba4167f4e31a35414f7198721cb9e7307f [file] [log] [blame]
<!--
~ Licensed to the Apache Software Foundation (ASF) under one
~ or more contributor license agreements. See the NOTICE file
~ distributed with this work for additional information
~ regarding copyright ownership. The ASF licenses this file
~ to you under the Apache License, Version 2.0 (the
~ "License"); you may not use this file except in compliance
~ with the License. You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing,
~ software distributed under the License is distributed on an
~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
~ KIND, either express or implied. See the License for the
~ specific language governing permissions and limitations
~ under the License.
-->
<section class="table-wrapper">
<table mat-table [dataSource]="filteredEnvironments" multiTemplateDataRows
class="data-grid resources mat-elevation-z6" [trackBy]="trackBy">
<ng-container matColumnDef="project">
<td mat-cell *matCellDef="let element" [attr.colspan]="8" class="project-name"> {{ element.project }} </td>
</ng-container>
<!-- <ng-container *ngFor="let column of filteringColumns; let i = index" matColumnDef="{{ column.name }}"
[attr.sticky]="column.name === 'name' ? true : null">
<th mat-header-cell *matHeaderCellDef ngClass="{{ column.class }}">
<span class="label">{{ column.title }}</span>
<button mat-icon-button *ngIf="column.filtering" aria-label="More" class="ar" (click)="toggleFilterRow()">
<i class="material-icons">
<span *ngIf="filtering && filterForm[column.name].length > 0 && !collapseFilterRow">filter_list</span>
<span [hidden]="filtering && filterForm[column.name].length > 0 && !collapseFilterRow">more_vert</span>
</i>
</button>
</th>
</ng-container> -->
<ng-container matColumnDef="name" sticky>
<th mat-header-cell *matHeaderCellDef class="name-col label-header">
<span class="label">Environment name</span>
<button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()">
<i class="material-icons">
<span *ngIf="filtering && filterForm.name.length > 0 && !collapseFilterRow">filter_list</span>
<span [hidden]="filtering && filterForm.name.length > 0 && !collapseFilterRow">more_vert</span>
</i>
</button>
</th>
</ng-container>
<ng-container matColumnDef="statuses">
<th mat-header-cell *matHeaderCellDef class="status-col label-header">
<span class="label"> Status </span>
<button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()">
<i class="material-icons">
<span *ngIf="filtering && filterForm.statuses.length > 0 && !collapseFilterRow">filter_list</span>
<span [hidden]="filtering && filterForm.statuses.length > 0 && !collapseFilterRow">more_vert</span>
</i>
</button>
</th>
</ng-container>
<ng-container matColumnDef="shapes">
<th mat-header-cell *matHeaderCellDef class="shape-col label-header">
<span class="label"> Size </span>
<button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()">
<i class="material-icons">
<span *ngIf="filtering && filterForm.shapes.length > 0 && !collapseFilterRow">filter_list</span>
<span [hidden]="filtering && filterForm.shapes.length > 0 && !collapseFilterRow">more_vert</span>
</i>
</button>
</th>
</ng-container>
<ng-container matColumnDef="tag">
<th mat-header-cell *matHeaderCellDef class="tag-col label-header">
<span class="label"> Tags </span>
<button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()">
<i class="material-icons">
<span>more_vert</span>
</i>
</button>
</th>
</ng-container>
<ng-container matColumnDef="resources">
<th mat-header-cell *matHeaderCellDef class="resources-col label-header">
<span class="label"> Compute </span>
<button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()">
<i class="material-icons">
<span *ngIf="filtering && filterForm.resources.length > 0 && !collapseFilterRow">filter_list</span>
<span [hidden]="filtering && filterForm.resources.length > 0 && !collapseFilterRow">more_vert</span>
</i>
</button>
</th>
</ng-container>
<ng-container matColumnDef="cost">
<th mat-header-cell *matHeaderCellDef class="cost-col label-header">
<span class="label"> Cost </span>
<button mat-icon-button aria-label="More" class="ar" (click)="toggleFilterRow()">
<i class="material-icons">
<span>more_vert</span>
</i>
</button>
</th>
</ng-container>
<ng-container matColumnDef="actions" stickyEnd>
<th mat-header-cell *matHeaderCellDef class="settings label-header">
<span class="label"> Actions </span>
</th>
</ng-container>
<!-- ----------------------------------------------------- -->
<ng-container matColumnDef="expandedDetail">
<td mat-cell *matCellDef="let element" class="exploratory" [attr.colspan]="8" sticky>
<!-- [@detailExpand]="element == expandedElement ? 'expanded' : 'collapsed'" -->
<tr *ngFor="let element of element.exploratory; let i = index" class="element-row mat-row">
<td class="name-col highlight" (click)="printDetailEnvironmentModal(element)">
<span matTooltip="{{ element.name }}" matTooltipPosition="above">{{ element.name }}</span>
</td>
<td class="status-col status" ngClass="{{ element.status.toLowerCase() || ''}}">
{{element.status | underscoreless }}
</td>
<td class="shape-col">{{ element.shape }}</td>
<td class="tag-col selection">
<mat-chip-list aria-label="Tags">
<mat-chip matTooltip="Endpoint tag: {{ element.tags.endpoint_tag }}" matTooltipPosition="above">
{{ element.tags.endpoint_tag }}
</mat-chip>
<mat-chip *ngIf="element.tags.custom_tag" matTooltip="Custom tag: {{ element.tags.custom_tag }}"
matTooltipPosition="above">
{{ element.tags.custom_tag }}
</mat-chip>
<mat-chip matTooltip="User tag: {{ element.tags.user_tag }}" matTooltipPosition="above">
{{ element.tags.user_tag }}
</mat-chip>
<mat-chip matTooltip="Project tag: {{ element.tags.project_tag }}" matTooltipPosition="above">
{{ element.tags.project_tag }}
</mat-chip>
</mat-chip-list>
</td>
<td class="resources-col">
<computational-resources-list [resources]="element.resources" [environment]="element"
(buildGrid)="buildGrid($event)">
</computational-resources-list>
</td>
<td *ngIf="healthStatus?.billingEnabled" class="cost-col">
<span class="total_cost">{{ element.billing.report_lines.length ? (element.cost | localcurrency) : 'N/A' }}</span>
<span (click)="element.billing && printCostDetails(element)" class="currency_details"
[ngClass]="{ 'not-allowed' : !element.billing.report_lines.length }">
<i class="material-icons">help_outline</i>
</span>
</td>
<td class="settings">
<span #settings (click)="actions.toggle($event, settings)" class="actions"
[ngClass]="{ 'disabled': element.status.toLowerCase() === 'creating'
|| (element.image === 'docker.datalab-superset' && element.status !== 'running' && element.status !== 'stopped')
|| (element.image === 'docker.datalab-jupyterlab' && element.status !== 'running' && element.status !== 'stopped') }">
</span>
<bubble-up #actions class="list-menu" position="bottom-left" alternative="top-left">
<ul class="list-unstyled">
<div class="active-items" *ngIf="element.status.toLowerCase() !== 'failed'
&& element.status !== 'terminating'
&& element.status !== 'terminated'
&& element.status !== 'creating image'">
<li
*ngIf="element.status !== 'stopped' && element.status !== 'stopping' && element.status !== 'starting' && element.status !== 'creating image' && element.status.toLowerCase() !== 'reconfiguring'"
matTooltip="Unable to stop notebook because at least one compute is in progress"
matTooltipPosition="above" [matTooltipDisabled]="!isResourcesInProgress(element)">
<div (click)="exploratoryAction(element, 'stop')"
[ngClass]="{'not-allowed': isResourcesInProgress(element) }">
<i class="material-icons">pause_circle_outline</i>
<span>Stop</span>
</div>
</li>
<li *ngIf="element.status.toLowerCase() === 'stopped' || element.status.toLowerCase() === 'stopping'"
matTooltip="{{element.edgeNodeStatus !== 'running' ? 'Unable to run notebook if edge node is not running.' : 'Unable to run notebook until it will be stopped.'}}" matTooltipPosition="above"
[matTooltipDisabled]="!isResourcesInProgress(element) && element.status.toLowerCase() !== 'stopping' && element.edgeNodeStatus === 'running'"
[ngClass]="{'not-allow': isResourcesInProgress(element) || element.status.toLowerCase() === 'stopping' || element.edgeNodeStatus !== 'running' }"
>
<div (click)="exploratoryAction(element, 'run')"
[ngClass]="{'not-allowed': isResourcesInProgress(element) || element.status.toLowerCase() === 'stopping' || element.edgeNodeStatus !== 'running' }">
<i class="material-icons">play_circle_outline</i>
<span>Run</span>
</div>
</li>
<li *ngIf="element.status.toLowerCase() === 'running' || element.status.toLowerCase() === 'stopped'"
matTooltip="Unable to terminate notebook because at least one compute is in progress"
matTooltipPosition="above" [matTooltipDisabled]="!isResourcesInProgress(element)">
<div (click)="exploratoryAction(element, 'terminate')"
[ngClass]="{'not-allowed': isResourcesInProgress(element) }">
<i class="material-icons">phonelink_off</i>
<span>Terminate</span>
</div>
</li>
<li
*ngIf="element.status === 'running' && element.image !== 'docker.datalab-superset' && element.image !== 'docker.datalab-jupyterlab'"
matTooltip="Only one compute can be associated with analytical tool at a time"
matTooltipPosition="above" [matTooltipDisabled]="!element.activeCompute"
[matTooltipClass]="'bucket-item-tooltip'"
[ngClass]="{'not-allow': element.activeCompute }"
>
<div
(click)="exploratoryAction(element, 'deploy')"
[ngClass]="{'not-allowed': element.activeCompute }"
>
<i class="material-icons">memory</i>
<span>Add compute</span>
</div>
</li>
<li (click)="exploratoryAction(element, 'schedule')" *ngIf="element.status.toLowerCase() === 'running'
|| element.status.toLowerCase() === 'stopped'">
<div>
<i class="material-icons">schedule</i>
<span>Scheduler</span>
</div>
</li>
</div>
<li (click)="exploratoryAction(element, 'ami')"
*ngIf="element.status === 'running' && element.image !== 'docker.datalab-superset' && element.image !== 'docker.datalab-jupyterlab'">
<div>
<i class="material-icons">view_module</i>
<span>Create AMI</span>
</div>
</li>
<li (click)="exploratoryAction(element, 'install')"
*ngIf="element.image !== 'docker.datalab-superset' && element.image !== 'docker.datalab-jupyterlab'">
<div>
<i class="material-icons">developer_board</i>
<span>Manage libraries</span>
</div>
</li>
<li *ngIf="element.status === 'running'" (click)="logAction(element.name)">
<div>
<a
target="_blank"
[attr.href]="'/#/terminal/' + element.private_ip + '/' + element.endpoint"
class="navigate"
(contextmenu)="false"
>
<i class="material-icons">laptop</i>
<span>Open terminal</span>
</a>
</div>
</li>
</ul>
</bubble-up>
</td>
</tr>
</td>
</ng-container>
<!-- FILTER START -->
<ng-container matColumnDef="name-filter" sticky>
<th mat-header-cell *matHeaderCellDef class="name-col filter-row-item">
<div class="input-wrapper">
<input placeholder="Filter by environment name" type="text" class="form-control filter-field"
[value]="filterForm.name" (input)="filterForm.name = $event.target['value']" (keyup)="checkFilters()"/>
</div>
</th>
</ng-container>
<ng-container matColumnDef="status-filter">
<th mat-header-cell *matHeaderCellDef class="status-col filter-row-item">
<multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="'statuses'"
[items]="filterConfiguration.statuses" [model]="filterForm.statuses"></multi-select-dropdown>
</th>
</ng-container>
<ng-container matColumnDef="shape-filter">
<th mat-header-cell *matHeaderCellDef class="shape-col filter-row-item">
<multi-select-dropdown (selectionChange)="onUpdate($event)"
[type]="'sizes'" [items]="filterConfiguration.shapes"
[model]="filterForm.shapes"></multi-select-dropdown>
</th>
</ng-container>
<ng-container matColumnDef="tag-filter">
<th mat-header-cell *matHeaderCellDef class="tag-col filter-row-item">
</th>
</ng-container>
<ng-container matColumnDef="resource-filter">
<th mat-header-cell *matHeaderCellDef class="resources-col filter-row-item">
<multi-select-dropdown (selectionChange)="onUpdate($event)" [type]="'resources'"
[items]="filterConfiguration.resources" [model]="filterForm.resources"></multi-select-dropdown>
</th>
</ng-container>
<ng-container matColumnDef="cost-filter">
<th mat-header-cell *matHeaderCellDef class="cost-col filter-row-item">
</th>
</ng-container>
<ng-container matColumnDef="action-filter" stickyEnd>
<th mat-header-cell *matHeaderCellDef>
<div class="actions">
<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" (click)="applyFilter_btnClick(filterForm)"
[disabled]="!isFilterChanged">
<i class="material-icons">done</i>
</button>
</div>
</th>
</ng-container>
<ng-container matColumnDef="placeholder">
<td mat-footer-cell *matFooterCellDef
[colSpan]="!healthStatus?.billingEnabled ? displayedFilterColumns.length -1 : displayedFilterColumns.length"
class="info">
<span *ngIf="(!filteredEnvironments) && !filtering || (filteredEnvironments.length == 0) && !filtering">
To start working, please, create new environment</span>
<span *ngIf="(filteredEnvironments.length == 0) && filtering">No matches found</span>
</td>
</ng-container>
<!-- FILTER END -->
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true" class="header-row"></tr>
<tr [hidden]="!collapseFilterRow" mat-header-row *matHeaderRowDef="displayedFilterColumns; sticky: true"
class="filter-row"></tr>
<tr mat-row *matRowDef="let element; columns: ['project']" class="element-row">
<!-- [class.expanded-row]="expandedElement === element"-->
<!-- (click)="expandedElement = expandedElement === element ? null : element">-->
</tr>
<tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="detail-row"></tr>
<tr [hidden]="filteredEnvironments?.length" mat-footer-row *matFooterRowDef="['placeholder']"></tr>
</table>
</section>