39 changed files with 959 additions and 164 deletions
@ -0,0 +1,49 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
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. |
||||
|
|
||||
|
--> |
||||
|
<ng-container *ngIf="simpleList; else complexEntityReferences"> |
||||
|
<ng-container *ngTemplateOutlet="referencesList; context:{entriesList: referencedEntitiesList, showDetailsLink: true}"></ng-container> |
||||
|
</ng-container> |
||||
|
<ng-template #complexEntityReferences> |
||||
|
<ng-container *ngIf="contentReady; else loading"> |
||||
|
<ul> |
||||
|
<ng-container *ngFor="let entry of referencedEntitiesEntries"> |
||||
|
<li *ngIf="isSystem(entry[0]); else tenantEntities"> |
||||
|
{{ 'image.system-entities' | translate }} |
||||
|
<ng-container *ngTemplateOutlet="referencesList; context:{entriesList: entry[1].entities, showDetailsLink: true}"></ng-container> |
||||
|
</li> |
||||
|
<ng-template #tenantEntities> |
||||
|
<li> |
||||
|
{{ 'tenant.tenant' | translate }} <a [routerLink]="entry[1].tenantDetailsUrl">{{ '"' + entry[1].tenantName + '"' }}</a> {{ 'image.entities' | translate }} |
||||
|
<ng-container *ngTemplateOutlet="referencesList; context:{entriesList: entry[1].entities, showDetailsLink: false}"></ng-container> |
||||
|
</li> |
||||
|
</ng-template> |
||||
|
</ng-container> |
||||
|
</ul> |
||||
|
</ng-container> |
||||
|
</ng-template> |
||||
|
<ng-template #referencesList let-entriesList="entriesList" let-showDetailsLink="showDetailsLink"> |
||||
|
<ul> |
||||
|
<li *ngFor="let referencedEntity of entriesList"> |
||||
|
{{ referencedEntity.typeName }} <a *ngIf="showDetailsLink" [routerLink]="referencedEntity.detailsUrl">{{ '"' + referencedEntity.entity.name + '"' }}</a> |
||||
|
<b *ngIf="!showDetailsLink">{{ '"' + referencedEntity.entity.name + '"' }}</b> |
||||
|
</li> |
||||
|
</ul> |
||||
|
</ng-template> |
||||
|
<ng-template #loading> |
||||
|
<mat-spinner [diameter]="32" strokeWidth="2"></mat-spinner> |
||||
|
</ng-template> |
||||
@ -0,0 +1,171 @@ |
|||||
|
///
|
||||
|
/// 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.
|
||||
|
///
|
||||
|
|
||||
|
import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; |
||||
|
import { Store } from '@ngrx/store'; |
||||
|
import { AppState } from '@core/core.state'; |
||||
|
import { ImageReferences } from '@shared/models/resource.models'; |
||||
|
import { EntityType, entityTypeTranslations } from '@shared/models/entity-type.models'; |
||||
|
import { TranslateService } from '@ngx-translate/core'; |
||||
|
import { getEntityDetailsPageURL } from '@core/utils'; |
||||
|
import { getCurrentAuthUser } from '@core/auth/auth.selectors'; |
||||
|
import { NULL_UUID } from '@shared/models/id/has-uuid'; |
||||
|
import { Authority } from '@shared/models/authority.enum'; |
||||
|
import { Observable } from 'rxjs'; |
||||
|
import { EntityService } from '@core/http/entity.service'; |
||||
|
import { BaseData, HasId } from '@shared/models/base-data'; |
||||
|
import { HasTenantId } from '@shared/models/entity.models'; |
||||
|
import { map } from 'rxjs/operators'; |
||||
|
import { TbPopoverComponent } from '@shared/components/popover.component'; |
||||
|
|
||||
|
interface ReferencedEntityInfo { |
||||
|
entity: BaseData<HasId> & HasTenantId; |
||||
|
typeName: string; |
||||
|
detailsUrl: string; |
||||
|
} |
||||
|
|
||||
|
interface TenantReferencedEntities { |
||||
|
tenantName?: string; |
||||
|
tenantDetailsUrl?: string; |
||||
|
entities: ReferencedEntityInfo[]; |
||||
|
} |
||||
|
|
||||
|
type ReferencedEntities = {[tenantId: string]: TenantReferencedEntities}; |
||||
|
type ReferencedEntitiesEntry = [string, TenantReferencedEntities]; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-image-references', |
||||
|
templateUrl: './image-references.component.html', |
||||
|
styleUrls: [] |
||||
|
}) |
||||
|
export class ImageReferencesComponent implements OnInit { |
||||
|
|
||||
|
@Input() |
||||
|
references: ImageReferences; |
||||
|
|
||||
|
popoverComponent: TbPopoverComponent<ImageReferencesComponent>; |
||||
|
|
||||
|
contentReady = false; |
||||
|
|
||||
|
authUser = getCurrentAuthUser(this.store); |
||||
|
|
||||
|
simpleList = true; |
||||
|
|
||||
|
referencedEntitiesList: ReferencedEntityInfo[]; |
||||
|
|
||||
|
referencedEntitiesEntries: ReferencedEntitiesEntry[]; |
||||
|
|
||||
|
constructor(protected store: Store<AppState>, |
||||
|
private entityService: EntityService, |
||||
|
private cd: ChangeDetectorRef, |
||||
|
private translate: TranslateService) { |
||||
|
} |
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
if (this.authUser.authority === Authority.SYS_ADMIN && this.hasNonSystemEntities(this.references)) { |
||||
|
this.simpleList = false; |
||||
|
this.toReferencedEntitiesEntries(this.references).subscribe( |
||||
|
(entries) => { |
||||
|
this.referencedEntitiesEntries = entries; |
||||
|
this.contentReady = true; |
||||
|
this.cd.detectChanges(); |
||||
|
if (this.popoverComponent) { |
||||
|
Promise.resolve().then(() => { |
||||
|
this.popoverComponent.updatePosition(); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
); |
||||
|
} else { |
||||
|
this.referencedEntitiesList = this.toReferencedEntitiesList(this.references); |
||||
|
this.contentReady = true; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
isSystem(tenantId: string): boolean { |
||||
|
return tenantId === NULL_UUID; |
||||
|
} |
||||
|
|
||||
|
private hasNonSystemEntities(references: ImageReferences): boolean { |
||||
|
for (const entityTypeStr of Object.keys(references)) { |
||||
|
const entities = this.references[entityTypeStr]; |
||||
|
if (entities.some(e => e.tenantId && e.tenantId.id && e.tenantId.id !== NULL_UUID)) { |
||||
|
return true; |
||||
|
} |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
private toReferencedEntitiesList(references: ImageReferences): ReferencedEntityInfo[] { |
||||
|
const result: ReferencedEntityInfo[] = []; |
||||
|
for (const entityTypeStr of Object.keys(references)) { |
||||
|
const entityType = entityTypeStr as EntityType; |
||||
|
const entityTypeName = this.translate.instant(entityTypeTranslations.get(entityType).type); |
||||
|
const entities = references[entityTypeStr]; |
||||
|
for (const entity of entities) { |
||||
|
const detailsUrl = getEntityDetailsPageURL(entity.id.id, entityType); |
||||
|
result.push({ |
||||
|
entity, |
||||
|
typeName: entityTypeName, |
||||
|
detailsUrl |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
private toReferencedEntitiesEntries(references: ImageReferences): Observable<ReferencedEntitiesEntry[]> { |
||||
|
let referencedEntities: ReferencedEntities = {}; |
||||
|
const referencedEntitiesList = this.toReferencedEntitiesList(references); |
||||
|
for (const referencedEntityInfo of referencedEntitiesList) { |
||||
|
const tenantId = referencedEntityInfo.entity.tenantId?.id || NULL_UUID; |
||||
|
let tenantEntitiesInfo = referencedEntities[tenantId]; |
||||
|
if (!tenantEntitiesInfo) { |
||||
|
tenantEntitiesInfo = { |
||||
|
entities: [] |
||||
|
}; |
||||
|
referencedEntities[tenantId] = tenantEntitiesInfo; |
||||
|
} |
||||
|
tenantEntitiesInfo.entities.push(referencedEntityInfo); |
||||
|
} |
||||
|
referencedEntities = Object.keys(referencedEntities).sort((tenantId1, tenantId2) => { |
||||
|
if (tenantId1 === NULL_UUID) { |
||||
|
return -1; |
||||
|
} else if (tenantId2 === NULL_UUID) { |
||||
|
return 1; |
||||
|
} |
||||
|
return 0; |
||||
|
}).reduce( |
||||
|
(obj, key) => { |
||||
|
obj[key] = referencedEntities[key]; |
||||
|
return obj; |
||||
|
}, |
||||
|
{} |
||||
|
); |
||||
|
const tenantIds = Object.keys(referencedEntities).filter(id => id !== NULL_UUID); |
||||
|
return this.entityService.getEntities(EntityType.TENANT, tenantIds).pipe( |
||||
|
map((tenants) => { |
||||
|
for (const tenant of tenants) { |
||||
|
const tenantEntitiesInfo = referencedEntities[tenant.id.id]; |
||||
|
tenantEntitiesInfo.tenantName = tenant.name; |
||||
|
tenantEntitiesInfo.tenantDetailsUrl = getEntityDetailsPageURL(tenant.id.id, EntityType.TENANT); |
||||
|
} |
||||
|
return Object.entries(referencedEntities); |
||||
|
}) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,130 @@ |
|||||
|
///
|
||||
|
/// 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.
|
||||
|
///
|
||||
|
|
||||
|
import { CollectionViewer, DataSource, SelectionModel } from '@angular/cdk/collections'; |
||||
|
import { ImageResourceInfo } from '@shared/models/resource.models'; |
||||
|
import { BehaviorSubject, Observable, of, ReplaySubject, Subject } from 'rxjs'; |
||||
|
import { emptyPageData, PageData } from '@shared/models/page/page-data'; |
||||
|
import { ImageService } from '@core/http/image.service'; |
||||
|
import { EntityBooleanFunction } from '@home/models/entity/entities-table-config.models'; |
||||
|
import { PageLink } from '@shared/models/page/page-link'; |
||||
|
import { catchError, map, take, tap } from 'rxjs/operators'; |
||||
|
|
||||
|
export class ImagesDatasource implements DataSource<ImageResourceInfo> { |
||||
|
private entitiesSubject: Subject<ImageResourceInfo[]>; |
||||
|
private readonly pageDataSubject: Subject<PageData<ImageResourceInfo>>; |
||||
|
|
||||
|
public pageData$: Observable<PageData<ImageResourceInfo>>; |
||||
|
|
||||
|
public selection = new SelectionModel<ImageResourceInfo>(true, []); |
||||
|
|
||||
|
public dataLoading = true; |
||||
|
|
||||
|
constructor(private imageService: ImageService, |
||||
|
private images: ImageResourceInfo[], |
||||
|
private selectionEnabledFunction: EntityBooleanFunction<ImageResourceInfo>) { |
||||
|
if (this.images && this.images.length) { |
||||
|
this.entitiesSubject = new BehaviorSubject<ImageResourceInfo[]>(this.images); |
||||
|
} else { |
||||
|
this.entitiesSubject = new BehaviorSubject<ImageResourceInfo[]>([]); |
||||
|
this.pageDataSubject = new BehaviorSubject<PageData<ImageResourceInfo>>(emptyPageData<ImageResourceInfo>()); |
||||
|
this.pageData$ = this.pageDataSubject.asObservable(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
connect(collectionViewer: CollectionViewer): |
||||
|
Observable<ImageResourceInfo[] | ReadonlyArray<ImageResourceInfo>> { |
||||
|
return this.entitiesSubject.asObservable(); |
||||
|
} |
||||
|
|
||||
|
disconnect(collectionViewer: CollectionViewer): void { |
||||
|
this.entitiesSubject.complete(); |
||||
|
if (this.pageDataSubject) { |
||||
|
this.pageDataSubject.complete(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
reset() { |
||||
|
this.entitiesSubject.next([]); |
||||
|
if (this.pageDataSubject) { |
||||
|
this.pageDataSubject.next(emptyPageData<ImageResourceInfo>()); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
loadEntities(pageLink: PageLink): Observable<PageData<ImageResourceInfo>> { |
||||
|
this.dataLoading = true; |
||||
|
const result = new ReplaySubject<PageData<ImageResourceInfo>>(); |
||||
|
this.fetchEntities(pageLink).pipe( |
||||
|
tap(() => { |
||||
|
this.selection.clear(); |
||||
|
}), |
||||
|
catchError(() => of(emptyPageData<ImageResourceInfo>())), |
||||
|
).subscribe( |
||||
|
(pageData) => { |
||||
|
this.entitiesSubject.next(pageData.data); |
||||
|
this.pageDataSubject.next(pageData); |
||||
|
result.next(pageData); |
||||
|
this.dataLoading = false; |
||||
|
} |
||||
|
); |
||||
|
return result; |
||||
|
} |
||||
|
|
||||
|
fetchEntities(pageLink: PageLink): Observable<PageData<ImageResourceInfo>> { |
||||
|
return this.imageService.getImages(pageLink); |
||||
|
} |
||||
|
|
||||
|
isAllSelected(): Observable<boolean> { |
||||
|
const numSelected = this.selection.selected.length; |
||||
|
return this.entitiesSubject.pipe( |
||||
|
map((entities) => numSelected === entities.length) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
isEmpty(): Observable<boolean> { |
||||
|
return this.entitiesSubject.pipe( |
||||
|
map((entities) => !entities.length) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
total(): Observable<number> { |
||||
|
return this.pageDataSubject.pipe( |
||||
|
map((pageData) => pageData.totalElements) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
masterToggle() { |
||||
|
this.entitiesSubject.pipe( |
||||
|
tap((entities) => { |
||||
|
const numSelected = this.selection.selected.length; |
||||
|
if (numSelected === this.selectableEntitiesCount(entities)) { |
||||
|
this.selection.clear(); |
||||
|
} else { |
||||
|
entities.forEach(row => { |
||||
|
if (this.selectionEnabledFunction(row)) { |
||||
|
this.selection.select(row); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
}), |
||||
|
take(1) |
||||
|
).subscribe(); |
||||
|
} |
||||
|
|
||||
|
private selectableEntitiesCount(entities: Array<ImageResourceInfo>): number { |
||||
|
return entities.filter((entity) => this.selectionEnabledFunction(entity)).length; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,82 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
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. |
||||
|
|
||||
|
--> |
||||
|
<h2 mat-dialog-title>{{title | translate}}</h2> |
||||
|
<div mat-dialog-content class="tb-images-in-use-content" [class]="{multiple: data.multiple}"> |
||||
|
<div [innerHTML]="message | translate | safe: 'html'"></div> |
||||
|
<ng-container *ngIf="data.multiple; else singleImageReferences"> |
||||
|
<div class="table-container"> |
||||
|
<table mat-table [dataSource]="dataSource"> |
||||
|
<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 style="width: 100%;"> |
||||
|
<ng-container *ngIf="dataSource.selection.isEmpty(); else selectedImages"> |
||||
|
{{ 'image.name' | translate }} |
||||
|
</ng-container> |
||||
|
<ng-template #selectedImages> |
||||
|
{{ translate.get('image.selected-images', {count: dataSource.selection.selected.length}) | async }} |
||||
|
</ng-template> |
||||
|
</mat-header-cell> |
||||
|
<mat-cell *matCellDef="let image"> |
||||
|
{{ image.title }} |
||||
|
</mat-cell> |
||||
|
</ng-container> |
||||
|
<ng-container matColumnDef="references"> |
||||
|
<mat-header-cell *matHeaderCellDef></mat-header-cell> |
||||
|
<mat-cell *matCellDef="let image"> |
||||
|
<button #showReferencesButton |
||||
|
mat-stroked-button |
||||
|
color="primary" |
||||
|
(click)="toggleShowReferences($event, image, showReferencesButton)">{{ 'image.references' | translate }}</button> |
||||
|
</mat-cell> |
||||
|
</ng-container> |
||||
|
<mat-header-row [ngClass]="{'mat-row-select': true}" *matHeaderRowDef="['select', 'preview', 'title', 'references']; sticky: true"></mat-header-row> |
||||
|
<mat-row [ngClass]="{'mat-row-select': true, |
||||
|
'mat-selected': dataSource.selection.isSelected(image)}" |
||||
|
*matRowDef="let image; columns: ['select', 'preview', 'title', 'references'];"></mat-row> |
||||
|
</table> |
||||
|
</div> |
||||
|
</ng-container> |
||||
|
</div> |
||||
|
<div mat-dialog-actions fxLayoutAlign="end center"> |
||||
|
<button mat-button color="primary" (click)="cancel()">{{'action.cancel' | translate}}</button> |
||||
|
<button mat-raised-button color="accent" (click)="delete()" [disabled]="data.multiple && dataSource.selection.isEmpty()" |
||||
|
cdkFocusInitial>{{ (data.multiple ? 'action.delete-selected' : 'action.delete-anyway') | translate}}</button> |
||||
|
</div> |
||||
|
<ng-template #singleImageReferences> |
||||
|
<tb-image-references [references]="references"></tb-image-references> |
||||
|
<div [innerHTML]="'image.delete-image-in-use-text' | translate | safe: 'html'"></div> |
||||
|
</ng-template> |
||||
@ -0,0 +1,39 @@ |
|||||
|
/** |
||||
|
* 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. |
||||
|
*/ |
||||
|
:host { |
||||
|
.tb-images-in-use-content { |
||||
|
display: flex; |
||||
|
flex-direction: column; |
||||
|
&.multiple { |
||||
|
gap: 16px; |
||||
|
} |
||||
|
.table-container { |
||||
|
overflow: auto; |
||||
|
.mat-mdc-cell.mat-column-preview { |
||||
|
width: 50px; |
||||
|
height: 50px; |
||||
|
padding: 2px 12px; |
||||
|
display: block; |
||||
|
} |
||||
|
} |
||||
|
.tb-image-preview { |
||||
|
width: 50px; |
||||
|
height: 50px; |
||||
|
object-fit: contain; |
||||
|
border-radius: 4px; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,112 @@ |
|||||
|
///
|
||||
|
/// 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.
|
||||
|
///
|
||||
|
|
||||
|
import { Component, Inject, OnInit, Renderer2, ViewContainerRef } from '@angular/core'; |
||||
|
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; |
||||
|
import { Store } from '@ngrx/store'; |
||||
|
import { AppState } from '@core/core.state'; |
||||
|
import { DialogComponent } from '@shared/components/dialog.component'; |
||||
|
import { Router } from '@angular/router'; |
||||
|
import { ImageReferences, ImageResourceInfo, ImageResourceInfoWithReferences } from '@shared/models/resource.models'; |
||||
|
import { ImagesDatasource } from '@home/components/image/images-datasource'; |
||||
|
import { MatButton } from '@angular/material/button'; |
||||
|
import { TbPopoverService } from '@shared/components/popover.service'; |
||||
|
import { ImageReferencesComponent } from '@home/components/image/image-references.component'; |
||||
|
import { TranslateService } from '@ngx-translate/core'; |
||||
|
|
||||
|
export interface ImagesInUseDialogData { |
||||
|
multiple: boolean; |
||||
|
images: ImageResourceInfoWithReferences[]; |
||||
|
} |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-images-in-use-dialog', |
||||
|
templateUrl: './images-in-use-dialog.component.html', |
||||
|
styleUrls: ['./images-in-use-dialog.component.scss'] |
||||
|
}) |
||||
|
export class ImagesInUseDialogComponent extends |
||||
|
DialogComponent<ImagesInUseDialogComponent, ImageResourceInfo[]> implements OnInit { |
||||
|
|
||||
|
title: string; |
||||
|
message: string; |
||||
|
|
||||
|
references: ImageReferences; |
||||
|
|
||||
|
dataSource: ImagesDatasource; |
||||
|
|
||||
|
constructor(protected store: Store<AppState>, |
||||
|
protected router: Router, |
||||
|
@Inject(MAT_DIALOG_DATA) public data: ImagesInUseDialogData, |
||||
|
public dialogRef: MatDialogRef<ImagesInUseDialogComponent, ImageResourceInfo[]>, |
||||
|
public translate: TranslateService, |
||||
|
private renderer: Renderer2, |
||||
|
private viewContainerRef: ViewContainerRef, |
||||
|
private popoverService: TbPopoverService) { |
||||
|
super(store, router, dialogRef); |
||||
|
} |
||||
|
|
||||
|
ngOnInit(): void { |
||||
|
if (this.data.multiple) { |
||||
|
this.title = 'image.images-are-in-use'; |
||||
|
this.message = 'image.images-are-in-use-text'; |
||||
|
this.dataSource = new ImagesDatasource(null, this.data.images, entity => true); |
||||
|
} else { |
||||
|
this.title = 'image.image-is-in-use'; |
||||
|
this.message = 'image.image-is-in-use-text'; |
||||
|
this.references = this.data.images[0].references; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
cancel() { |
||||
|
this.dialogRef.close(null); |
||||
|
} |
||||
|
|
||||
|
delete() { |
||||
|
if (this.data.multiple) { |
||||
|
this.dialogRef.close(this.dataSource.selection.selected); |
||||
|
} else { |
||||
|
this.dialogRef.close(this.data.images); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
toggleShowReferences($event: Event, image: ImageResourceInfoWithReferences, referencesButton: MatButton) { |
||||
|
if ($event) { |
||||
|
$event.stopPropagation(); |
||||
|
} |
||||
|
const trigger = referencesButton._elementRef.nativeElement; |
||||
|
if (this.popoverService.hasPopover(trigger)) { |
||||
|
this.popoverService.hidePopover(trigger); |
||||
|
} else { |
||||
|
const referencesPopover = this.popoverService.displayPopover(trigger, this.renderer, |
||||
|
this.viewContainerRef, ImageReferencesComponent, 'top', true, null, |
||||
|
{ |
||||
|
references: image.references |
||||
|
}, {}, {}, {}, |
||||
|
false, |
||||
|
visible => { |
||||
|
const addClasses = visible ? 'mdc-button--unelevated mat-mdc-unelevated-button' : 'mdc-button--outlined mat-mdc-outlined-button'; |
||||
|
const removeClasses = visible ? 'mdc-button--outlined mat-mdc-outlined-button' : 'mdc-button--unelevated mat-mdc-unelevated-button'; |
||||
|
addClasses.split(' ').forEach(clazz => { |
||||
|
this.renderer.addClass(trigger, clazz); |
||||
|
}); |
||||
|
removeClasses.split(' ').forEach(clazz => { |
||||
|
this.renderer.removeClass(trigger, clazz); |
||||
|
}); |
||||
|
}); |
||||
|
referencesPopover.tbComponentRef.instance.popoverComponent = referencesPopover; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue