Browse Source

UI: Add widget panel: implement all widgets mode.

feature/widget-bundles
Igor Kulikov 3 years ago
parent
commit
c783e44ac6
  1. 11
      application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java
  2. 2
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetTypesEdgeEventFetcher.java
  3. 2
      application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantWidgetTypesEdgeEventFetcher.java
  4. 6
      common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java
  5. 9
      dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java
  6. 22
      dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeRepository.java
  7. 6
      dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeDao.java
  8. 20
      dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java
  9. 6
      ui-ngx/src/app/core/http/widget.service.ts
  10. 16
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html
  11. 34
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.html
  12. 111
      ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.ts
  13. 2
      ui-ngx/src/assets/locale/locale.constant-en_US.json

11
application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java

@ -74,6 +74,7 @@ public class WidgetTypeController extends AutoCommitController {
"Those properties are useful to edit the Widget Type but they are not required for Dashboard rendering. ";
private static final String WIDGET_TYPE_INFO_DESCRIPTION = "Widget Type Info is a lightweight object that represents Widget Type but does not contain the heavyweight widget descriptor JSON";
private static final String TENANT_ONLY_PARAM_DESCRIPTION = "Optional boolean parameter indicating whether only tenant widget types should be returned";
private static final String FULL_SEARCH_PARAM_DESCRIPTION = "Optional boolean parameter indicating whether search widgets by description not only by name";
private static final String UPDATE_EXISTING_BY_FQN_PARAM_DESCRIPTION = "Optional boolean parameter indicating whether to update existing widget type by FQN if present instead of creating new one";
@ApiOperation(value = "Get Widget Type Details (getWidgetTypeById)",
@ -163,15 +164,17 @@ public class WidgetTypeController extends AutoCommitController {
@ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES)
@RequestParam(required = false) String sortOrder,
@ApiParam(value = TENANT_ONLY_PARAM_DESCRIPTION)
@RequestParam(required = false) Boolean tenantOnly) throws ThingsboardException {
@RequestParam(required = false) Boolean tenantOnly,
@ApiParam(value = FULL_SEARCH_PARAM_DESCRIPTION)
@RequestParam(required = false) Boolean fullSearch) throws ThingsboardException {
PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder);
if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) {
return checkNotNull(widgetTypeService.findSystemWidgetTypesByPageLink(getTenantId(), pageLink));
return checkNotNull(widgetTypeService.findSystemWidgetTypesByPageLink(getTenantId(), fullSearch != null && fullSearch, pageLink));
} else {
if (tenantOnly != null && tenantOnly) {
return checkNotNull(widgetTypeService.findTenantWidgetTypesByTenantIdAndPageLink(getTenantId(), pageLink));
return checkNotNull(widgetTypeService.findTenantWidgetTypesByTenantIdAndPageLink(getTenantId(), fullSearch != null && fullSearch, pageLink));
} else {
return checkNotNull(widgetTypeService.findAllTenantWidgetTypesByTenantIdAndPageLink(getTenantId(), pageLink));
return checkNotNull(widgetTypeService.findAllTenantWidgetTypesByTenantIdAndPageLink(getTenantId(), fullSearch != null && fullSearch, pageLink));
}
}
}

2
application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetTypesEdgeEventFetcher.java

@ -31,6 +31,6 @@ public class SystemWidgetTypesEdgeEventFetcher extends BaseWidgetTypesEdgeEventF
@Override
protected PageData<WidgetTypeInfo> findWidgetTypes(TenantId tenantId, PageLink pageLink) {
return widgetTypeService.findSystemWidgetTypesByPageLink(tenantId, pageLink);
return widgetTypeService.findSystemWidgetTypesByPageLink(tenantId, false, pageLink);
}
}

2
application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantWidgetTypesEdgeEventFetcher.java

@ -30,6 +30,6 @@ public class TenantWidgetTypesEdgeEventFetcher extends BaseWidgetTypesEdgeEventF
}
@Override
protected PageData<WidgetTypeInfo> findWidgetTypes(TenantId tenantId, PageLink pageLink) {
return widgetTypeService.findTenantWidgetTypesByTenantIdAndPageLink(tenantId, pageLink);
return widgetTypeService.findTenantWidgetTypesByTenantIdAndPageLink(tenantId, false, pageLink);
}
}

6
common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java

@ -39,11 +39,11 @@ public interface WidgetTypeService extends EntityDaoService {
void deleteWidgetType(TenantId tenantId, WidgetTypeId widgetTypeId);
PageData<WidgetTypeInfo> findSystemWidgetTypesByPageLink(TenantId tenantId, PageLink pageLink);
PageData<WidgetTypeInfo> findSystemWidgetTypesByPageLink(TenantId tenantId, boolean fullSearch, PageLink pageLink);
PageData<WidgetTypeInfo> findAllTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, PageLink pageLink);
PageData<WidgetTypeInfo> findAllTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, PageLink pageLink);
PageData<WidgetTypeInfo> findTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, PageLink pageLink);
PageData<WidgetTypeInfo> findTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, PageLink pageLink);
List<WidgetType> findWidgetTypesByWidgetsBundleId(TenantId tenantId, WidgetsBundleId widgetsBundleId);

9
dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java

@ -78,33 +78,36 @@ public class JpaWidgetTypeDao extends JpaAbstractDao<WidgetTypeDetailsEntity, Wi
}
@Override
public PageData<WidgetTypeInfo> findSystemWidgetTypes(TenantId tenantId, PageLink pageLink) {
public PageData<WidgetTypeInfo> findSystemWidgetTypes(TenantId tenantId, boolean fullSearch, PageLink pageLink) {
return DaoUtil.toPageData(
widgetTypeRepository
.findSystemWidgetTypes(
NULL_UUID,
Objects.toString(pageLink.getTextSearch(), ""),
fullSearch,
DaoUtil.toPageable(pageLink)));
}
@Override
public PageData<WidgetTypeInfo> findAllTenantWidgetTypesByTenantId(UUID tenantId, PageLink pageLink) {
public PageData<WidgetTypeInfo> findAllTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, PageLink pageLink) {
return DaoUtil.toPageData(
widgetTypeRepository
.findAllTenantWidgetTypesByTenantId(
tenantId,
NULL_UUID,
Objects.toString(pageLink.getTextSearch(), ""),
fullSearch,
DaoUtil.toPageable(pageLink)));
}
@Override
public PageData<WidgetTypeInfo> findTenantWidgetTypesByTenantId(UUID tenantId, PageLink pageLink) {
public PageData<WidgetTypeInfo> findTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, PageLink pageLink) {
return DaoUtil.toPageData(
widgetTypeRepository
.findTenantWidgetTypesByTenantId(
tenantId,
Objects.toString(pageLink.getTextSearch(), ""),
fullSearch,
DaoUtil.toPageable(pageLink)));
}

22
dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeRepository.java

@ -38,23 +38,29 @@ public interface WidgetTypeRepository extends JpaRepository<WidgetTypeDetailsEnt
boolean existsByTenantIdAndId(UUID tenantId, UUID id);
@Query("SELECT new org.thingsboard.server.dao.model.sql.WidgetTypeInfoEntity(wtd) FROM WidgetTypeDetailsEntity wtd WHERE wtd.tenantId = :systemTenantId " +
"AND LOWER(wtd.name) LIKE LOWER(CONCAT('%', :searchText, '%'))")
"AND (LOWER(wtd.name) LIKE LOWER(CONCAT('%', :searchText, '%')) " +
"OR ((:fullSearch) IS TRUE AND LOWER(wtd.description) LIKE LOWER(CONCAT('%', :searchText, '%'))))")
Page<WidgetTypeInfoEntity> findSystemWidgetTypes(@Param("systemTenantId") UUID systemTenantId,
@Param("searchText") String searchText,
@Param("fullSearch") boolean fullSearch,
Pageable pageable);
@Query("SELECT new org.thingsboard.server.dao.model.sql.WidgetTypeInfoEntity(wtd) FROM WidgetTypeDetailsEntity wtd WHERE wtd.tenantId IN (:tenantId, :nullTenantId) " +
"AND LOWER(wtd.name) LIKE LOWER(CONCAT('%', :textSearch, '%'))")
"AND (LOWER(wtd.name) LIKE LOWER(CONCAT('%', :searchText, '%')) " +
"OR ((:fullSearch) IS TRUE AND LOWER(wtd.description) LIKE LOWER(CONCAT('%', :searchText, '%'))))")
Page<WidgetTypeInfoEntity> findAllTenantWidgetTypesByTenantId(@Param("tenantId") UUID tenantId,
@Param("nullTenantId") UUID nullTenantId,
@Param("textSearch") String textSearch,
Pageable pageable);
@Param("nullTenantId") UUID nullTenantId,
@Param("searchText") String searchText,
@Param("fullSearch") boolean fullSearch,
Pageable pageable);
@Query("SELECT new org.thingsboard.server.dao.model.sql.WidgetTypeInfoEntity(wtd) FROM WidgetTypeDetailsEntity wtd WHERE wtd.tenantId = :tenantId " +
"AND LOWER(wtd.name) LIKE LOWER(CONCAT('%', :textSearch, '%'))")
"AND (LOWER(wtd.name) LIKE LOWER(CONCAT('%', :searchText, '%')) " +
"OR ((:fullSearch) IS TRUE AND LOWER(wtd.description) LIKE LOWER(CONCAT('%', :searchText, '%'))))")
Page<WidgetTypeInfoEntity> findTenantWidgetTypesByTenantId(@Param("tenantId") UUID tenantId,
@Param("textSearch") String textSearch,
Pageable pageable);
@Param("searchText") String searchText,
@Param("fullSearch") boolean fullSearch,
Pageable pageable);
@Query("SELECT wtd FROM WidgetTypeDetailsEntity wtd WHERE wtd.tenantId = :tenantId " +
"AND LOWER(wtd.name) LIKE LOWER(CONCAT('%', :textSearch, '%'))")

6
dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeDao.java

@ -53,11 +53,11 @@ public interface WidgetTypeDao extends Dao<WidgetTypeDetails>, ExportableEntityD
boolean existsByTenantIdAndId(TenantId tenantId, UUID widgetTypeId);
PageData<WidgetTypeInfo> findSystemWidgetTypes(TenantId tenantId, PageLink pageLink);
PageData<WidgetTypeInfo> findSystemWidgetTypes(TenantId tenantId, boolean fullSearch, PageLink pageLink);
PageData<WidgetTypeInfo> findAllTenantWidgetTypesByTenantId(UUID tenantId, PageLink pageLink);
PageData<WidgetTypeInfo> findAllTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, PageLink pageLink);
PageData<WidgetTypeInfo> findTenantWidgetTypesByTenantId(UUID tenantId, PageLink pageLink);
PageData<WidgetTypeInfo> findTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, PageLink pageLink);
/**
* Find widget types by widgetsBundleId.

20
dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeServiceImpl.java

@ -110,26 +110,26 @@ public class WidgetTypeServiceImpl implements WidgetTypeService {
}
@Override
public PageData<WidgetTypeInfo> findSystemWidgetTypesByPageLink(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findSystemWidgetTypesByPageLink, pageLink [{}]", pageLink);
public PageData<WidgetTypeInfo> findSystemWidgetTypesByPageLink(TenantId tenantId, boolean fullSearch, PageLink pageLink) {
log.trace("Executing findSystemWidgetTypesByPageLink, fullSearch [{}] pageLink [{}]", fullSearch, pageLink);
Validator.validatePageLink(pageLink);
return widgetTypeDao.findSystemWidgetTypes(tenantId, pageLink);
return widgetTypeDao.findSystemWidgetTypes(tenantId, fullSearch, pageLink);
}
@Override
public PageData<WidgetTypeInfo> findAllTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findAllTenantWidgetTypesByTenantIdAndPageLink, tenantId [{}], pageLink [{}]", tenantId, pageLink);
public PageData<WidgetTypeInfo> findAllTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, PageLink pageLink) {
log.trace("Executing findAllTenantWidgetTypesByTenantIdAndPageLink, tenantId [{}], fullSearch [{}], pageLink [{}]", tenantId, fullSearch, pageLink);
Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
Validator.validatePageLink(pageLink);
return widgetTypeDao.findAllTenantWidgetTypesByTenantId(tenantId.getId(), pageLink);
return widgetTypeDao.findAllTenantWidgetTypesByTenantId(tenantId.getId(), fullSearch, pageLink);
}
@Override
public PageData<WidgetTypeInfo> findTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, PageLink pageLink) {
log.trace("Executing findTenantWidgetTypesByTenantIdAndPageLink, tenantId [{}], pageLink [{}]", tenantId, pageLink);
public PageData<WidgetTypeInfo> findTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, PageLink pageLink) {
log.trace("Executing findTenantWidgetTypesByTenantIdAndPageLink, tenantId [{}], fullSearch [{}], pageLink [{}]", tenantId, fullSearch, pageLink);
Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId);
Validator.validatePageLink(pageLink);
return widgetTypeDao.findTenantWidgetTypesByTenantId(tenantId.getId(), pageLink);
return widgetTypeDao.findTenantWidgetTypesByTenantId(tenantId.getId(), fullSearch, pageLink);
}
@Override
@ -227,7 +227,7 @@ public class WidgetTypeServiceImpl implements WidgetTypeService {
@Override
protected PageData<WidgetTypeInfo> findEntities(TenantId tenantId, TenantId id, PageLink pageLink) {
return widgetTypeDao.findTenantWidgetTypesByTenantId(id.getId(), pageLink);
return widgetTypeDao.findTenantWidgetTypesByTenantId(id.getId(), false, pageLink);
}
@Override

6
ui-ngx/src/app/core/http/widget.service.ts

@ -223,8 +223,10 @@ export class WidgetService {
));
}
public getWidgetTypes(pageLink: PageLink, tenantOnly = false, config?: RequestConfig): Observable<PageData<WidgetTypeInfo>> {
return this.http.get<PageData<WidgetTypeInfo>>(`/api/widgetTypes${pageLink.toQuery()}&tenantOnly=${tenantOnly}`,
public getWidgetTypes(pageLink: PageLink, tenantOnly = false,
fullSearch = false, config?: RequestConfig): Observable<PageData<WidgetTypeInfo>> {
return this.http.get<PageData<WidgetTypeInfo>>(
`/api/widgetTypes${pageLink.toQuery()}&tenantOnly=${tenantOnly}&fullSearch=${fullSearch}`,
defaultHttpOptionsFromConfig(config));
}

16
ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html

@ -386,8 +386,9 @@
</tb-details-panel>
<tb-details-panel *ngIf="!isAddingWidgetClosed && !widgetEditMode" fxFlex
headerTitle="{{ isAddingWidget ?
((!dashboardWidgetSelectComponent?.widgetsBundle ?
'widget.select-widgets-bundle' : 'dashboard.select-widget-value') | translate: dashboardWidgetSelectComponent?.widgetsBundle) : ''
((dashboardWidgetSelectComponent?.selectWidgetMode === 'allWidgets' ? ('widget.select-widget' | translate) :
(!dashboardWidgetSelectComponent?.widgetsBundle ?
'widget.select-widgets-bundle' : 'dashboard.select-widget-value') | translate: dashboardWidgetSelectComponent?.widgetsBundle)) : ''
}}"
headerHeightPx="64"
[isShowSearch]="true"
@ -404,7 +405,8 @@
<div class="search-pane" *ngIf="isAddingWidget" fxLayout="row">
<tb-widgets-bundle-search fxFlex
[(ngModel)]="searchBundle"
placeholder="{{ (!dashboardWidgetSelectComponent?.widgetsBundle ? 'widgets-bundle.search' : 'widget.search') | translate }}"
placeholder="{{ ((!dashboardWidgetSelectComponent?.widgetsBundle && dashboardWidgetSelectComponent?.selectWidgetMode === 'bundles')
? 'widgets-bundle.search' : 'widget.search') | translate }}"
(ngModelChange)="searchBundle = $event">
</tb-widgets-bundle-search>
</div>
@ -419,6 +421,14 @@
matTooltipPosition="above">
<mat-icon>filter_list</mat-icon>
</button>
<tb-toggle-select *ngIf="dashboardWidgetSelectComponent && !dashboardWidgetSelectComponent.widgetsBundle"
appearance="fill-invert"
disablePagination
selectMediaBreakpoint="xs"
[(ngModel)]="dashboardWidgetSelectComponent.selectWidgetMode">
<tb-toggle-option value="bundles">{{ 'widgets-bundle.widgets-bundles' | translate }}</tb-toggle-option>
<tb-toggle-option value="allWidgets">{{ 'widget.all-widgets' | translate }}</tb-toggle-option>
</tb-toggle-select>
<tb-toggle-select *ngIf="dashboardWidgetSelectComponent?.hasDeprecated"
appearance="fill-invert"
disablePagination

34
ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.html

@ -16,9 +16,17 @@
-->
<div class="widget-select">
<div *ngIf="widgetsBundle; else bundles">
<div *ngIf="(widgets$ | async)?.length; else loadingWidgets" fxFlexFill fxLayoutGap="12px grid" fxLayout="row wrap">
<div *ngFor="let widget of widgets$ | async" class="mat-card-container">
<ng-container *ngIf="selectWidgetMode === 'bundles'; else allWidgets">
<div *ngIf="widgetsBundle; else bundles">
<ng-container *ngTemplateOutlet="widgets; context:{ currentWidgets$: widgets$ }"></ng-container>
</div>
</ng-container>
<ng-template #allWidgets>
<ng-container *ngTemplateOutlet="widgets; context:{ currentWidgets$: allWidgets$ }"></ng-container>
</ng-template>
<ng-template #widgets let-currentWidgets$="currentWidgets$">
<div *ngIf="(currentWidgets$ | async)?.length; else loadingWidgets" fxFlexFill fxLayoutGap="12px grid" fxLayout="row wrap">
<div *ngFor="let widget of currentWidgets$ | async" class="mat-card-container">
<mat-card appearance="raised" fxFlexFill fxLayout="row" fxLayoutGap="16px" (click)="onWidgetClicked($event, widget)">
<div class="preview-container" fxFlex="45">
<img class="preview" [src]="getPreviewImage(widget.image)" alt="{{ widget.title }}">
@ -33,22 +41,22 @@
</mat-card>
</div>
</div>
<ng-template #loadingWidgets>
<div *ngIf="loadingWidgets$ | async; else emptyBundle" fxLayout="column"
fxLayoutAlign="center center" class="tb-absolute-fill">
</ng-template>
<ng-template #loadingWidgets>
<div *ngIf="loadingWidgets$ | async; else emptyBundle" fxLayout="column"
fxLayoutAlign="center center" class="tb-absolute-fill">
<span class="mat-headline-5" style="padding-bottom: 20px;">
{{ 'widget.loading-widgets' | translate }}
</span>
<mat-spinner color="accent" strokeWidth="5"></mat-spinner>
</div>
<ng-template #emptyBundle>
<mat-spinner color="accent" strokeWidth="5"></mat-spinner>
</div>
</ng-template>
<ng-template #emptyBundle>
<span translate
style="display: flex;"
fxLayoutAlign="center center"
class="mat-headline-5 tb-absolute-fill">widgets-bundle.empty</span>
</ng-template>
</ng-template>
</div>
class="mat-headline-5 tb-absolute-fill">{{(selectWidgetMode === 'bundles' ? 'widgets-bundle.empty' : 'widget.no-widgets-text') | translate}}</span>
</ng-template>
<ng-template #bundles>
<div *ngIf="(widgetsBundles$ | async)?.length; else loadingWidgetBundles" fxFlexFill fxLayoutGap="12px grid" fxLayout="row wrap">
<div *ngFor="let widgetsBundle of widgetsBundles$ | async" class="mat-card-container">

111
ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.ts

@ -19,14 +19,18 @@ import { WidgetsBundle } from '@shared/models/widgets-bundle.model';
import { IAliasController } from '@core/api/widget-api.models';
import { NULL_UUID } from '@shared/models/id/has-uuid';
import { WidgetService } from '@core/http/widget.service';
import { fullWidgetTypeFqn, WidgetInfo, widgetType } from '@shared/models/widget.models';
import { distinctUntilChanged, map, publishReplay, refCount, share, switchMap, tap } from 'rxjs/operators';
import { BehaviorSubject, combineLatest, Observable, of } from 'rxjs';
import { fullWidgetTypeFqn, WidgetInfo, widgetType, WidgetTypeInfo } from '@shared/models/widget.models';
import { debounceTime, distinctUntilChanged, map, share, switchMap, tap } from 'rxjs/operators';
import { BehaviorSubject, combineLatest, Observable, of, ReplaySubject } from 'rxjs';
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
import { isDefinedAndNotNull } from '@core/utils';
import { PageLink } from '@shared/models/page/page-link';
import { Direction } from '@shared/models/page/sort-order';
type widgetsListMode = 'all' | 'actual' | 'deprecated';
type selectWidgetMode = 'bundles' | 'allWidgets';
@Component({
selector: 'tb-dashboard-widget-select',
templateUrl: './dashboard-widget-select.component.html',
@ -37,11 +41,13 @@ export class DashboardWidgetSelectComponent implements OnInit {
private search$ = new BehaviorSubject<string>('');
private filterWidgetTypes$ = new BehaviorSubject<Array<widgetType>>(null);
private widgetsListMode$ = new BehaviorSubject<widgetsListMode>('actual');
private selectWidgetMode$ = new BehaviorSubject<selectWidgetMode>('bundles');
private widgetsInfo: Observable<Array<WidgetInfo>>;
private widgetsBundleValue: WidgetsBundle;
widgetTypes = new Set<widgetType>();
hasDeprecated = false;
allWidgets$: Observable<Array<WidgetInfo>>;
widgets$: Observable<Array<WidgetInfo>>;
loadingWidgetsSubject: BehaviorSubject<boolean> = new BehaviorSubject(false);
loadingWidgets$ = this.loadingWidgetsSubject.pipe(
@ -87,6 +93,15 @@ export class DashboardWidgetSelectComponent implements OnInit {
return this.filterWidgetTypes$.value;
}
@Input()
set selectWidgetMode(mode: selectWidgetMode) {
this.selectWidgetMode$.next(mode);
}
get selectWidgetMode(): selectWidgetMode {
return this.selectWidgetMode$.value;
}
@Input()
set widgetsListMode(mode: widgetsListMode) {
this.widgetsListMode$.next(mode);
@ -105,13 +120,20 @@ export class DashboardWidgetSelectComponent implements OnInit {
constructor(private widgetsService: WidgetService,
private sanitizer: DomSanitizer,
private cd: ChangeDetectorRef) {
this.widgetsBundles$ = this.search$.asObservable().pipe(
distinctUntilChanged(),
switchMap(search => this.fetchWidgetBundle(search))
this.widgetsBundles$ = combineLatest([this.search$.asObservable(), this.selectWidgetMode$.asObservable()]).pipe(
distinctUntilChanged((oldValue, newValue) => JSON.stringify(oldValue) === JSON.stringify(newValue)),
switchMap(search => this.fetchWidgetBundle(...search))
);
this.allWidgets$ = combineLatest([this.search$.asObservable().pipe(
debounceTime(150)
), this.selectWidgetMode$.asObservable()]).pipe(
distinctUntilChanged((oldValue, newValue) => JSON.stringify(oldValue) === JSON.stringify(newValue)),
switchMap(search => this.fetchAllWidgets(...search)),
share({ connector: () => new ReplaySubject(1), resetOnError: false, resetOnComplete: false, resetOnRefCountZero: false })
);
this.widgets$ = combineLatest([this.search$.asObservable(), this.filterWidgetTypes$.asObservable(), this.widgetsListMode$]).pipe(
distinctUntilChanged((oldValue, newValue) => JSON.stringify(oldValue) === JSON.stringify(newValue)),
switchMap(search => this.fetchWidget(...search))
switchMap(search => this.fetchWidgets(...search))
);
}
@ -128,15 +150,7 @@ export class DashboardWidgetSelectComponent implements OnInit {
const hasDeprecated = widgets.some(w => w.deprecated);
const widgetInfos = widgets.map((widgetTypeInfo) => {
widgetTypes.add(widgetTypeInfo.widgetType);
const widget: WidgetInfo = {
typeFullFqn: fullWidgetTypeFqn(widgetTypeInfo),
type: widgetTypeInfo.widgetType,
title: widgetTypeInfo.name,
image: widgetTypeInfo.image,
description: widgetTypeInfo.description,
deprecated: widgetTypeInfo.deprecated
};
return widget;
return this.toWidgetInfo(widgetTypeInfo);
}
);
setTimeout(() => {
@ -149,8 +163,7 @@ export class DashboardWidgetSelectComponent implements OnInit {
tap(() => {
this.loadingWidgetsSubject.next(false);
}),
publishReplay(1),
refCount()
share({ connector: () => new ReplaySubject(1), resetOnError: false, resetOnComplete: false, resetOnRefCountZero: false })
);
} else {
this.widgetsInfo = of([]);
@ -181,26 +194,29 @@ export class DashboardWidgetSelectComponent implements OnInit {
return '/assets/widget-preview-empty.svg';
}
private getWidgetsBundle(): Observable<Array<WidgetsBundle>> {
private getWidgetsBundles(): Observable<Array<WidgetsBundle>> {
return this.widgetsService.getAllWidgetsBundles().pipe(
tap(() => this.loadingWidgetBundlesSubject.next(false)),
publishReplay(1),
refCount()
share({ connector: () => new ReplaySubject(1), resetOnError: false, resetOnComplete: false, resetOnRefCountZero: false })
);
}
private fetchWidgetBundle(search: string): Observable<Array<WidgetsBundle>> {
return this.getWidgetsBundle().pipe(
map(bundles => search ? bundles.filter(
bundle => (
bundle.title?.toLowerCase().includes(search.toLowerCase()) ||
bundle.description?.toLowerCase().includes(search.toLowerCase())
)) : bundles
)
);
private fetchWidgetBundle(search: string, mode: selectWidgetMode): Observable<Array<WidgetsBundle>> {
if (mode === 'bundles') {
return this.getWidgetsBundles().pipe(
map(bundles => search ? bundles.filter(
bundle => (
bundle.title?.toLowerCase().includes(search.toLowerCase()) ||
bundle.description?.toLowerCase().includes(search.toLowerCase())
)) : bundles
)
);
} else {
return of([]);
}
}
private fetchWidget(search: string, filter: widgetType[], listMode: widgetsListMode): Observable<Array<WidgetInfo>> {
private fetchWidgets(search: string, filter: widgetType[], listMode: widgetsListMode): Observable<Array<WidgetInfo>> {
return this.getWidgets().pipe(
map(widgets => (listMode && listMode !== 'all') ?
widgets.filter((widget) => listMode === 'actual' ? !widget.deprecated : widget.deprecated) : widgets),
@ -213,4 +229,37 @@ export class DashboardWidgetSelectComponent implements OnInit {
)
);
}
private fetchAllWidgets(search: string, mode: selectWidgetMode): Observable<Array<WidgetInfo>> {
if (mode === 'allWidgets') {
const pageLink = new PageLink(1024, 0, search, {
property: 'name',
direction: Direction.ASC
});
return this.getAllWidgets(pageLink);
} else {
return of([]);
}
}
private getAllWidgets(pageLink: PageLink): Observable<Array<WidgetInfo>> {
this.loadingWidgetsSubject.next(true);
return this.widgetsService.getWidgetTypes(pageLink, false, true).pipe(
map(data => data.data.map(w => this.toWidgetInfo(w))),
tap(() => {
this.loadingWidgetsSubject.next(false);
})
);
}
private toWidgetInfo(widgetTypeInfo: WidgetTypeInfo): WidgetInfo {
return {
typeFullFqn: fullWidgetTypeFqn(widgetTypeInfo),
type: widgetTypeInfo.widgetType,
title: widgetTypeInfo.name,
image: widgetTypeInfo.image,
description: widgetTypeInfo.description,
deprecated: widgetTypeInfo.deprecated
};
}
}

2
ui-ngx/src/assets/locale/locale.constant-en_US.json

@ -4531,10 +4531,12 @@
"all-bundles": "All bundles",
"select-widgets-bundle": "Select widgets bundle",
"widgets": "Widgets",
"all-widgets": "All widgets",
"widget": "Widget",
"select-widget": "Select widget",
"no-widgets-matching": "No widgets matching '{{entity}}' were found.",
"no-widgets": "No widgets yet",
"no-widgets-text": "No widgets found",
"management": "Widget management",
"editor": "Widget Editor",
"widget-type-not-found": "Problem loading widget configuration.<br>Probably associated\n widget type was removed.",

Loading…
Cancel
Save