From 271da436ac1be6a9ad4351e9cf20c1f54037d05e Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 23 Nov 2023 19:34:31 +0200 Subject: [PATCH] UI: Include system images switch. --- .../server/controller/ImageController.java | 2 +- ui-ngx/src/app/core/http/image.service.ts | 6 +- .../image/image-gallery.component.html | 129 ++++++++++-------- .../image/image-gallery.component.scss | 12 ++ .../image/image-gallery.component.ts | 58 ++++++-- .../components/image/images-datasource.ts | 8 +- .../assets/locale/locale.constant-en_US.json | 3 +- 7 files changed, 142 insertions(+), 76 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/ImageController.java b/application/src/main/java/org/thingsboard/server/controller/ImageController.java index 3bfd342cad..121ecbb921 100644 --- a/application/src/main/java/org/thingsboard/server/controller/ImageController.java +++ b/application/src/main/java/org/thingsboard/server/controller/ImageController.java @@ -208,7 +208,7 @@ public class ImageController extends BaseController { // PE: generic permission PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); TenantId tenantId = getTenantId(); - if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN || includeSystemImages) { + if (getCurrentUser().getAuthority() == Authority.SYS_ADMIN || !includeSystemImages) { return checkNotNull(imageService.getImagesByTenantId(tenantId, pageLink)); } else { return checkNotNull(imageService.getAllImagesByTenantId(tenantId, pageLink)); diff --git a/ui-ngx/src/app/core/http/image.service.ts b/ui-ngx/src/app/core/http/image.service.ts index cde43b0d8b..abce29d9e3 100644 --- a/ui-ngx/src/app/core/http/image.service.ts +++ b/ui-ngx/src/app/core/http/image.service.ts @@ -69,8 +69,10 @@ export class ImageService { imageInfo, defaultHttpOptionsFromConfig(config)); } - public getImages(pageLink: PageLink, config?: RequestConfig): Observable> { - return this.http.get>(`${IMAGES_URL_PREFIX}${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config)); + public getImages(pageLink: PageLink, includeSystemImages = false, config?: RequestConfig): Observable> { + return this.http.get>( + `${IMAGES_URL_PREFIX}${pageLink.toQuery()}&includeSystemImages=${includeSystemImages}`, + defaultHttpOptionsFromConfig(config)); } public getImageInfo(type: ImageResourceType, key: string, config?: RequestConfig): Observable { diff --git a/ui-ngx/src/app/modules/home/components/image/image-gallery.component.html b/ui-ngx/src/app/modules/home/components/image/image-gallery.component.html index e09981d676..96eb9c7be9 100644 --- a/ui-ngx/src/app/modules/home/components/image/image-gallery.component.html +++ b/ui-ngx/src/app/modules/home/components/image/image-gallery.component.html @@ -17,70 +17,81 @@ -->
- -
- image.gallery -
-
- -
-
- + +
+
+ image.gallery +
+
+ +
+
+ +
+ {{ 'image.include-system-images' | translate }}
-
-
- -
- - - - + + + +
+
- - +
+ {{ 'image.include-system-images' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/image/image-gallery.component.scss b/ui-ngx/src/app/modules/home/components/image/image-gallery.component.scss index 0216445bee..0b7b5e3c65 100644 --- a/ui-ngx/src/app/modules/home/components/image/image-gallery.component.scss +++ b/ui-ngx/src/app/modules/home/components/image/image-gallery.component.scss @@ -28,6 +28,18 @@ $tb-button-selected-color: rgb(255, 110, 64) !default; border-radius: 4px; } + .mat-mdc-table-toolbar { + &.multi-row { + &.mat-toolbar-single-row { + height: 112px; + } + .mat-mdc-slide-toggle { + display: flex; + min-height: 48px; + } + } + } + .tb-images-title { padding-right: 20px; white-space: nowrap; diff --git a/ui-ngx/src/app/modules/home/components/image/image-gallery.component.ts b/ui-ngx/src/app/modules/home/components/image/image-gallery.component.ts index 1b59f34455..43938f2515 100644 --- a/ui-ngx/src/app/modules/home/components/image/image-gallery.component.ts +++ b/ui-ngx/src/app/modules/home/components/image/image-gallery.component.ts @@ -69,6 +69,11 @@ import { } from '@home/components/image/images-in-use-dialog.component'; import { ImagesDatasource } from '@home/components/image/images-datasource'; +interface GridImagesFilter { + search: string; + includeSystemImages: boolean; +} + @Component({ selector: 'tb-image-gallery', templateUrl: './image-gallery.component.html', @@ -104,6 +109,7 @@ export class ImageGalleryComponent extends PageComponent implements OnInit, OnDe dataSource: ImagesDatasource; textSearch = this.fb.control('', {nonNullable: true}); + includeSystemImages = this.fb.control(false); gridColumns: ScrollGridColumns = { columns: 2, @@ -118,8 +124,11 @@ export class ImageGalleryComponent extends PageComponent implements OnInit, OnDe } }; - gridImagesFetchFunction: GridEntitiesFetchFunction; - gridImagesFilter = ''; + gridImagesFetchFunction: GridEntitiesFetchFunction; + gridImagesFilter: GridImagesFilter = { + search: '', + includeSystemImages: false + }; gridImagesItemSizeStrategy: ItemSizeStrategy = { defaultItemSize: 200, @@ -148,16 +157,16 @@ export class ImageGalleryComponent extends PageComponent implements OnInit, OnDe super(store); this.gridImagesFetchFunction = (pageSize, page, filter) => { - const pageLink = new PageLink(pageSize, page, filter, { + const pageLink = new PageLink(pageSize, page, filter.search, { property: 'createdTime', direction: Direction.DESC }); - return this.imageService.getImages(pageLink); + return this.imageService.getImages(pageLink, filter.includeSystemImages); }; } ngOnInit(): void { - this.displayedColumns = ['select', 'preview', 'title', 'createdTime', 'resolution', 'size', 'system', 'actions']; + this.displayedColumns = this.computeDisplayedColumns(); let sortOrder: SortOrder = this.defaultSortOrder; this.pageSizeOptions = [this.defaultPageSize, this.defaultPageSize * 2, this.defaultPageSize * 3]; const routerQueryParams: PageQueryParam = this.route.snapshot.queryParams; @@ -208,7 +217,7 @@ export class ImageGalleryComponent extends PageComponent implements OnInit, OnDe this.textSearch.valueChanges.pipe( debounceTime(150), distinctUntilChanged((prev, current) => - ((this.mode === 'list' ? this.pageLink.textSearch : this.gridImagesFilter) ?? '') === current.trim()), + ((this.mode === 'list' ? this.pageLink.textSearch : this.gridImagesFilter.search) ?? '') === current.trim()), takeUntil(this.destroy$) ).subscribe(value => { if (this.mode === 'list') { @@ -224,7 +233,25 @@ export class ImageGalleryComponent extends PageComponent implements OnInit, OnDe this.updateData(); } } else { - this.gridImagesFilter = isNotEmptyStr(value) ? value.trim() : null; + this.gridImagesFilter = { + search: isNotEmptyStr(value) ? encodeURI(value) : null, + includeSystemImages: this.includeSystemImages.value + }; + this.cd.markForCheck(); + } + }); + this.includeSystemImages.valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe(value => { + this.displayedColumns = this.computeDisplayedColumns(); + this.gridImagesFilter = { + search: this.gridImagesFilter.search, + includeSystemImages: value + }; + if (this.mode === 'list') { + this.paginator.pageIndex = 0; + this.updateData(); + } else { this.cd.markForCheck(); } }); @@ -253,6 +280,19 @@ export class ImageGalleryComponent extends PageComponent implements OnInit, OnDe } } + public get isSysAdmin(): boolean { + return this.authUser.authority === Authority.SYS_ADMIN; + } + + private computeDisplayedColumns(): string[] { + const columns = ['select', 'preview', 'title', 'createdTime', 'resolution', 'size']; + if (!this.isSysAdmin && this.includeSystemImages.value) { + columns.push('system'); + } + columns.push('actions'); + return columns; + } + private updateMode() { if (this.mode === 'list') { this.initListMode(); @@ -346,7 +386,7 @@ export class ImageGalleryComponent extends PageComponent implements OnInit, OnDe } else { this.pageLink.sortOrder = null; } - this.dataSource.loadEntities(this.pageLink); + this.dataSource.loadEntities(this.pageLink, this.includeSystemImages.value); } else { this.gridComponent.update(); } @@ -386,7 +426,7 @@ export class ImageGalleryComponent extends PageComponent implements OnInit, OnDe } isSystem(image?: ImageResourceInfo): boolean { - return image?.tenantId?.id === NULL_UUID; + return !this.isSysAdmin && image?.tenantId?.id === NULL_UUID; } readonly(image?: ImageResourceInfo): boolean { diff --git a/ui-ngx/src/app/modules/home/components/image/images-datasource.ts b/ui-ngx/src/app/modules/home/components/image/images-datasource.ts index 604b96d25b..8be2f30cc0 100644 --- a/ui-ngx/src/app/modules/home/components/image/images-datasource.ts +++ b/ui-ngx/src/app/modules/home/components/image/images-datasource.ts @@ -64,10 +64,10 @@ export class ImagesDatasource implements DataSource { } } - loadEntities(pageLink: PageLink): Observable> { + loadEntities(pageLink: PageLink, includeSystemImages = false): Observable> { this.dataLoading = true; const result = new ReplaySubject>(); - this.fetchEntities(pageLink).pipe( + this.fetchEntities(pageLink, includeSystemImages).pipe( tap(() => { this.selection.clear(); }), @@ -83,8 +83,8 @@ export class ImagesDatasource implements DataSource { return result; } - fetchEntities(pageLink: PageLink): Observable> { - return this.imageService.getImages(pageLink); + fetchEntities(pageLink: PageLink, includeSystemImages = false): Observable> { + return this.imageService.getImages(pageLink, includeSystemImages); } isAllSelected(): Observable { diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index b48cd84a5e..9bd9ef140c 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2981,7 +2981,8 @@ "delete-image-in-use-text": "If you still want to delete the image, click the Delete anyway button.", "system-entities": "System entities:", "entities": "entities:", - "references": "References" + "references": "References", + "include-system-images": "Include system images" }, "image-input": { "drop-images-or": "Drag and drop an images or",