thingsboard/ui-ngx/src/app/modules/home/components/image/image-gallery.component.html

270 lines
12 KiB
HTML
Raw Normal View History

2023-11-21 11:27:37 +02:00
<!--
Copyright © 2016-2023 The Thingsboard Authors
Licensed 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.
-->
<div class="mat-padding tb-images tb-absolute-fill" [ngClass]="{'mat-padding': pageMode}">
<div fxFlex fxLayout="column" class="tb-images-content" [ngClass]="{'tb-outlined-border': pageMode}">
<mat-toolbar class="mat-mdc-table-toolbar" [fxShow]="!textSearchMode && dataSource.selection.isEmpty()">
<div class="mat-toolbar-tools">
<span class="tb-images-title" translate>image.gallery</span>
<div class="tb-images-view-type-toolbar"
fxLayout="row"
fxLayoutAlign="start center">
<div class="tb-toolbar-button" [ngClass]="{'tb-selected' : mode === 'list'}">
<button mat-icon-button
(click)="setMode('list')"
matTooltip="{{'image.list-mode' | translate }}"
matTooltipPosition="below">
<mat-icon>view_list</mat-icon>
</button>
</div>
<div class="tb-toolbar-button" [ngClass]="{'tb-selected' : mode === 'grid'}">
<button mat-icon-button
(click)="setMode('grid');"
matTooltip="{{'image.grid-mode' | translate }}"
matTooltipPosition="below">
<tb-icon>mdi:view-grid</tb-icon>
</button>
</div>
</div>
</div>
<section fxFlex fxLayout="row" fxLayoutAlign="start center" fxLayoutGap="16px">
<span fxFlex></span>
<section fxLayout="row">
<button [disabled]="isLoading$ | async"
mat-icon-button
(click)="enterFilterMode()"
matTooltip="{{'action.search' | translate }}"
matTooltipPosition="above">
<mat-icon>search</mat-icon>
</button>
<button [disabled]="isLoading$ | async"
mat-icon-button
(click)="updateData()"
matTooltip="{{'action.refresh' | translate }}"
matTooltipPosition="above">
<mat-icon>refresh</mat-icon>
</button>
<button [disabled]="isLoading$ | async"
mat-icon-button
(click)="importImage()"
matTooltip="{{'image.import-image' | translate }}"
matTooltipPosition="above">
<mat-icon>upload</mat-icon>
</button>
</section>
<button [disabled]="isLoading$ | async"
mat-flat-button
color="primary"
(click)="uploadImage()">
{{ 'image.upload-image' | translate }}
</button>
</section>
</mat-toolbar>
<mat-toolbar class="mat-mdc-table-toolbar" [fxShow]="textSearchMode && dataSource.selection.isEmpty()">
<div class="mat-toolbar-tools">
<button mat-icon-button
matTooltip="{{ 'image.search' | translate }}"
matTooltipPosition="above">
<mat-icon>search</mat-icon>
</button>
<mat-form-field fxFlex>
<mat-label>&nbsp;</mat-label>
<input #searchInput matInput
[formControl]="textSearch"
placeholder="{{ 'image.search' | translate }}"/>
</mat-form-field>
<button mat-icon-button (click)="exitFilterMode()"
matTooltip="{{ 'action.close' | translate }}"
matTooltipPosition="above">
<mat-icon>close</mat-icon>
</button>
</div>
</mat-toolbar>
<mat-toolbar class="mat-mdc-table-toolbar" color="primary" [fxShow]="!dataSource.selection.isEmpty()">
<div class="mat-toolbar-tools">
<span>
{{ translate.get('image.selected-images', {count: dataSource.selection.selected.length}) | async }}
</span>
<span fxFlex></span>
<button mat-icon-button [disabled]="isLoading$ | async"
matTooltip="{{ 'action.delete' | translate }}"
matTooltipPosition="above"
(click)="deleteImages($event)">
<mat-icon>delete</mat-icon>
</button>
</div>
</mat-toolbar>
<div fxFlex *ngIf="mode === 'list'" fxLayout="column">
<div fxFlex class="table-container">
2023-11-21 14:08:52 +02:00
<table mat-table [dataSource]="dataSource" [trackBy]="trackByEntity"
2023-11-21 11:27:37 +02:00
matSort [matSortActive]="pageLink.sortOrder.property" [matSortDirection]="pageLink.sortDirection()" matSortDisableClear>
<ng-container matColumnDef="select" sticky>
<mat-header-cell *matHeaderCellDef style="width: 30px;">
<mat-checkbox (change)="$event ? dataSource.masterToggle() : null"
[checked]="dataSource.selection.hasValue() && (dataSource.isAllSelected() | async)"
[indeterminate]="dataSource.selection.hasValue() && (dataSource.isAllSelected() | async) === false">
</mat-checkbox>
</mat-header-cell>
<mat-cell *matCellDef="let image">
<mat-checkbox (click)="$event.stopPropagation()"
(change)="$event ? dataSource.selection.toggle(image) : null"
[checked]="dataSource.selection.isSelected(image)">
</mat-checkbox>
</mat-cell>
</ng-container>
<ng-container matColumnDef="preview">
<mat-header-cell *matHeaderCellDef style="width: 50px; min-width: 50px;"></mat-header-cell>
<mat-cell *matCellDef="let image">
<img class="tb-image-preview" [src]="image.link | image: {preview: true} | async" alt="{{ image.title }}">
</mat-cell>
</ng-container>
<ng-container matColumnDef="title">
<mat-header-cell *matHeaderCellDef mat-sort-header style="width: 100%;"> {{ 'image.name' | translate }} </mat-header-cell>
<mat-cell *matCellDef="let image">
{{ image.title }}
</mat-cell>
</ng-container>
<ng-container matColumnDef="createdTime">
<mat-header-cell *matHeaderCellDef mat-sort-header style="width: 200px; min-width: 200px;"> {{ 'image.created-time' | translate }} </mat-header-cell>
<mat-cell *matCellDef="let image">
{{ image.createdTime | date:'yyyy-MM-dd HH:mm:ss' }}
</mat-cell>
</ng-container>
<ng-container matColumnDef="resolution">
<mat-header-cell *matHeaderCellDef style="width: 160px; min-width: 160px;"> {{ 'image.resolution' | translate }} </mat-header-cell>
<mat-cell *matCellDef="let image">
{{ image.descriptor.width }}x{{ image.descriptor.height }}
</mat-cell>
</ng-container>
<ng-container matColumnDef="size">
<mat-header-cell *matHeaderCellDef style="width: 160px; min-width: 160px;"> {{ 'image.size' | translate }} </mat-header-cell>
<mat-cell *matCellDef="let image">
{{ image.descriptor.size | fileSize }}
</mat-cell>
</ng-container>
<ng-container matColumnDef="system">
<mat-header-cell *matHeaderCellDef style="width: 60px; min-width: 60px;"> {{ 'image.system' | translate }} </mat-header-cell>
<mat-cell *matCellDef="let image">
<mat-icon class="material-icons mat-icon">{{isSystem(image) ? 'check_box' : 'check_box_outline_blank'}}</mat-icon>
</mat-cell>
</ng-container>
<ng-container matColumnDef="actions" stickyEnd>
<mat-header-cell *matHeaderCellDef style="min-width: 192px; max-width: 192px; width: 192px">
</mat-header-cell>
<mat-cell *matCellDef="let image">
<div fxFlex fxLayout="row" fxLayoutAlign="end">
<button mat-icon-button [disabled]="isLoading$ | async"
matTooltip="{{ 'image.download-image' | translate }}"
matTooltipPosition="above"
(click)="downloadImage($event, image)">
<mat-icon>file_download</mat-icon>
</button>
<button mat-icon-button [disabled]="isLoading$ | async"
matTooltip="{{ 'image.export-image' | translate }}"
matTooltipPosition="above"
(click)="exportImage($event, image)">
<tb-icon>mdi:file-export</tb-icon>
</button>
<button mat-icon-button [disabled]="isLoading$ | async"
matTooltip="{{ 'image.edit-image' | translate }}"
matTooltipPosition="above"
(click)="editImage($event, image)">
<mat-icon>edit</mat-icon>
</button>
2023-11-21 14:08:52 +02:00
<button mat-icon-button [disabled]="(isLoading$ | async) || readonly(image)"
2023-11-21 11:27:37 +02:00
matTooltip="{{ 'image.delete-image' | translate }}"
matTooltipPosition="above"
(click)="deleteImage($event, image)">
<mat-icon>delete</mat-icon>
</button>
</div>
</mat-cell>
</ng-container>
<mat-header-row [ngClass]="{'mat-row-select': true}" *matHeaderRowDef="displayedColumns; sticky: true"></mat-header-row>
<mat-row [ngClass]="{'mat-row-select': true,
'mat-selected': dataSource.selection.isSelected(image)}"
*matRowDef="let image; columns: displayedColumns;" (click)="dataSource.selection.toggle(image)"></mat-row>
</table>
<ng-container *ngIf="(dataSource.isEmpty() | async) && !dataSource.dataLoading">
<ng-container *ngTemplateOutlet="noImages"></ng-container>
</ng-container>
<span [fxShow]="dataSource.dataLoading"
fxLayoutAlign="center center"
class="no-data-found">{{ 'common.loading' | translate }}</span>
</div>
<mat-divider></mat-divider>
<mat-paginator [length]="dataSource.total() | async"
[pageIndex]="pageLink.page"
[pageSize]="pageLink.pageSize"
[pageSizeOptions]="pageSizeOptions"
[hidePageSize]="hidePageSize"
showFirstLastButtons></mat-paginator>
</div>
<div fxFlex class="mat-padding" *ngIf="mode === 'grid'" fxLayout="column">
<tb-scroll-grid fxFlex
[columns]="gridColumns"
[itemSize]="150"
[fetchFunction]="gridImagesFetchFunction"
[filter]="gridImagesFilter"
[itemCard]="imageCard"
[loadingCell]="imageLoadingCard"
[dataLoading]="loadingImages"
[noData]="noImages">
</tb-scroll-grid>
</div>
</div>
</div>
<ng-template #loadingImages>
<div fxLayout="column"
fxLayoutAlign="center center" class="tb-absolute-fill">
<span class="mat-headline-5" style="padding-bottom: 20px;">
{{ 'common.loading' | translate }}
</span>
<mat-spinner color="accent" strokeWidth="5"></mat-spinner>
</div>
</ng-template>
<ng-template #noImages>
<div class="tb-no-images">
<div class="tb-no-data-bg"></div>
<div class="tb-no-data-text" translate>image.no-images</div>
</div>
</ng-template>
<ng-template #imageCard let-item="item">
<div class="tb-image-card">
<div class="tb-image-preview-container">
<div class="tb-image-preview-spacer"></div>
<img class="tb-image-preview" [src]="item.link | image: {preview: true} | async" alt="{{ item.title }}">
</div>
<div class="tb-image-details">
<div class="tb-image-title-container">
<div class="tb-image-title">
{{ item.title }}
</div>
<div *ngIf="isSystem(item)" class="tb-image-sys">sys</div>
</div>
<div class="tb-image-info-container">
<div>{{ item.descriptor.width }}x{{ item.descriptor.height }}</div>
<mat-divider vertical></mat-divider>
<div>{{ item.descriptor.size | fileSize }}</div>
</div>
</div>
</div>
</ng-template>
<ng-template #imageLoadingCard>
<div> TODO </div>
</ng-template>