Commit 620b66b7008abfacb9f15b7bb4a699e4834c864e

Authored by Andrii Shvaika
2 parents c4fd267f 416432e3

Merge branch 'develop/3.0' of github.com:thingsboard/thingsboard into develop/3.0

@@ -44,6 +44,8 @@ import org.thingsboard.server.common.data.page.TimePageLink; @@ -44,6 +44,8 @@ import org.thingsboard.server.common.data.page.TimePageLink;
44 import org.thingsboard.server.service.security.permission.Operation; 44 import org.thingsboard.server.service.security.permission.Operation;
45 import org.thingsboard.server.service.security.permission.Resource; 45 import org.thingsboard.server.service.security.permission.Resource;
46 46
  47 +import java.util.UUID;
  48 +
47 @RestController 49 @RestController
48 @RequestMapping("/api") 50 @RequestMapping("/api")
49 public class AlarmController extends BaseController { 51 public class AlarmController extends BaseController {
@@ -155,6 +157,7 @@ public class AlarmController extends BaseController { @@ -155,6 +157,7 @@ public class AlarmController extends BaseController {
155 @RequestParam(required = false) String sortOrder, 157 @RequestParam(required = false) String sortOrder,
156 @RequestParam(required = false) Long startTime, 158 @RequestParam(required = false) Long startTime,
157 @RequestParam(required = false) Long endTime, 159 @RequestParam(required = false) Long endTime,
  160 + @RequestParam(required = false) String offset,
158 @RequestParam(required = false) Boolean fetchOriginator 161 @RequestParam(required = false) Boolean fetchOriginator
159 ) throws ThingsboardException { 162 ) throws ThingsboardException {
160 checkParameter("EntityId", strEntityId); 163 checkParameter("EntityId", strEntityId);
@@ -168,8 +171,12 @@ public class AlarmController extends BaseController { @@ -168,8 +171,12 @@ public class AlarmController extends BaseController {
168 } 171 }
169 checkEntityId(entityId, Operation.READ); 172 checkEntityId(entityId, Operation.READ);
170 TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime); 173 TimePageLink pageLink = createTimePageLink(pageSize, page, textSearch, sortProperty, sortOrder, startTime, endTime);
  174 + UUID idOffsetUuid = null;
  175 + if (StringUtils.isNotEmpty(offset)) {
  176 + idOffsetUuid = toUUID(offset);
  177 + }
171 try { 178 try {
172 - return checkNotNull(alarmService.findAlarms(getCurrentUser().getTenantId(), new AlarmQuery(entityId, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator)).get()); 179 + return checkNotNull(alarmService.findAlarms(getCurrentUser().getTenantId(), new AlarmQuery(entityId, pageLink, alarmSearchStatus, alarmStatus, fetchOriginator, idOffsetUuid)).get());
173 } catch (Exception e) { 180 } catch (Exception e) {
174 throw handleException(e); 181 throw handleException(e);
175 } 182 }
@@ -22,6 +22,8 @@ import org.thingsboard.server.common.data.id.EntityId; @@ -22,6 +22,8 @@ import org.thingsboard.server.common.data.id.EntityId;
22 import org.thingsboard.server.common.data.id.TenantId; 22 import org.thingsboard.server.common.data.id.TenantId;
23 import org.thingsboard.server.common.data.page.TimePageLink; 23 import org.thingsboard.server.common.data.page.TimePageLink;
24 24
  25 +import java.util.UUID;
  26 +
25 /** 27 /**
26 * Created by ashvayka on 11.05.17. 28 * Created by ashvayka on 11.05.17.
27 */ 29 */
@@ -35,5 +37,6 @@ public class AlarmQuery { @@ -35,5 +37,6 @@ public class AlarmQuery {
35 private AlarmSearchStatus searchStatus; 37 private AlarmSearchStatus searchStatus;
36 private AlarmStatus status; 38 private AlarmStatus status;
37 private Boolean fetchOriginator; 39 private Boolean fetchOriginator;
  40 + private UUID idOffset;
38 41
39 } 42 }
@@ -300,7 +300,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ @@ -300,7 +300,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ
300 AlarmSeverity highestSeverity = null; 300 AlarmSeverity highestSeverity = null;
301 AlarmQuery query; 301 AlarmQuery query;
302 while (hasNext && AlarmSeverity.CRITICAL != highestSeverity) { 302 while (hasNext && AlarmSeverity.CRITICAL != highestSeverity) {
303 - query = new AlarmQuery(entityId, nextPageLink, alarmSearchStatus, alarmStatus, false); 303 + query = new AlarmQuery(entityId, nextPageLink, alarmSearchStatus, alarmStatus, false, null);
304 PageData<AlarmInfo> alarms = alarmDao.findAlarms(tenantId, query); 304 PageData<AlarmInfo> alarms = alarmDao.findAlarms(tenantId, query);
305 if (alarms.hasNext()) { 305 if (alarms.hasNext()) {
306 nextPageLink = nextPageLink.nextPageLink(); 306 nextPageLink = nextPageLink.nextPageLink();
@@ -33,7 +33,7 @@ import java.util.List; @@ -33,7 +33,7 @@ import java.util.List;
33 @SqlDao 33 @SqlDao
34 public interface AlarmRepository extends CrudRepository<AlarmEntity, String> { 34 public interface AlarmRepository extends CrudRepository<AlarmEntity, String> {
35 35
36 - @Query("SELECT a FROM AlarmEntity a WHERE a.originatorId = :originatorId AND a.type = :alarmType ORDER BY startTs DESC") 36 + @Query("SELECT a FROM AlarmEntity a WHERE a.originatorId = :originatorId AND a.type = :alarmType ORDER BY a.startTs DESC")
37 List<AlarmEntity> findLatestByOriginatorAndType(@Param("originatorId") String originatorId, 37 List<AlarmEntity> findLatestByOriginatorAndType(@Param("originatorId") String originatorId,
38 @Param("alarmType") String alarmType, 38 @Param("alarmType") String alarmType,
39 Pageable pageable); 39 Pageable pageable);
@@ -48,6 +48,7 @@ public interface AlarmRepository extends CrudRepository<AlarmEntity, String> { @@ -48,6 +48,7 @@ public interface AlarmRepository extends CrudRepository<AlarmEntity, String> {
48 "AND re.fromType = :affectedEntityType " + 48 "AND re.fromType = :affectedEntityType " +
49 "AND (:startId IS NULL OR a.id >= :startId) " + 49 "AND (:startId IS NULL OR a.id >= :startId) " +
50 "AND (:endId IS NULL OR a.id <= :endId) " + 50 "AND (:endId IS NULL OR a.id <= :endId) " +
  51 + "AND (:idOffset IS NULL OR a.id < :idOffset) " +
51 "AND (LOWER(a.type) LIKE LOWER(CONCAT(:searchText, '%'))" + 52 "AND (LOWER(a.type) LIKE LOWER(CONCAT(:searchText, '%'))" +
52 "OR LOWER(a.severity) LIKE LOWER(CONCAT(:searchText, '%'))" + 53 "OR LOWER(a.severity) LIKE LOWER(CONCAT(:searchText, '%'))" +
53 "OR LOWER(a.status) LIKE LOWER(CONCAT(:searchText, '%')))") 54 "OR LOWER(a.status) LIKE LOWER(CONCAT(:searchText, '%')))")
@@ -57,6 +58,7 @@ public interface AlarmRepository extends CrudRepository<AlarmEntity, String> { @@ -57,6 +58,7 @@ public interface AlarmRepository extends CrudRepository<AlarmEntity, String> {
57 @Param("relationType") String relationType, 58 @Param("relationType") String relationType,
58 @Param("startId") String startId, 59 @Param("startId") String startId,
59 @Param("endId") String endId, 60 @Param("endId") String endId,
  61 + @Param("idOffset") String idOffset,
60 @Param("searchText") String searchText, 62 @Param("searchText") String searchText,
61 Pageable pageable); 63 Pageable pageable);
62 } 64 }
@@ -117,6 +117,7 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A @@ -117,6 +117,7 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A
117 relationType, 117 relationType,
118 startTimeToId(query.getPageLink().getStartTime()), 118 startTimeToId(query.getPageLink().getStartTime()),
119 endTimeToId(query.getPageLink().getEndTime()), 119 endTimeToId(query.getPageLink().getEndTime()),
  120 + query.getIdOffset() != null ? UUIDConverter.fromTimeUUID(query.getIdOffset()) : null,
120 Objects.toString(query.getPageLink().getTextSearch(), ""), 121 Objects.toString(query.getPageLink().getTextSearch(), ""),
121 DaoUtil.toPageable(query.getPageLink()) 122 DaoUtil.toPageable(query.getPageLink())
122 ) 123 )
@@ -190,6 +190,8 @@ export interface WidgetSubscriptionOptions { @@ -190,6 +190,8 @@ export interface WidgetSubscriptionOptions {
190 alarmSource?: Datasource; 190 alarmSource?: Datasource;
191 alarmSearchStatus?: AlarmSearchStatus; 191 alarmSearchStatus?: AlarmSearchStatus;
192 alarmsPollingInterval?: number; 192 alarmsPollingInterval?: number;
  193 + alarmsMaxCountLoad?: number;
  194 + alarmsFetchSize?: number;
193 datasources?: Array<Datasource>; 195 datasources?: Array<Datasource>;
194 targetDeviceAliasIds?: Array<string>; 196 targetDeviceAliasIds?: Array<string>;
195 targetDeviceIds?: Array<string>; 197 targetDeviceIds?: Array<string>;
@@ -93,6 +93,8 @@ export class WidgetSubscription implements IWidgetSubscription { @@ -93,6 +93,8 @@ export class WidgetSubscription implements IWidgetSubscription {
93 } 93 }
94 94
95 alarmsPollingInterval: number; 95 alarmsPollingInterval: number;
  96 + alarmsMaxCountLoad: number;
  97 + alarmsFetchSize: number;
96 alarmSourceListener: AlarmSourceListener; 98 alarmSourceListener: AlarmSourceListener;
97 99
98 loadingData: boolean; 100 loadingData: boolean;
@@ -153,6 +155,10 @@ export class WidgetSubscription implements IWidgetSubscription { @@ -153,6 +155,10 @@ export class WidgetSubscription implements IWidgetSubscription {
153 options.alarmSearchStatus : AlarmSearchStatus.ANY; 155 options.alarmSearchStatus : AlarmSearchStatus.ANY;
154 this.alarmsPollingInterval = isDefined(options.alarmsPollingInterval) ? 156 this.alarmsPollingInterval = isDefined(options.alarmsPollingInterval) ?
155 options.alarmsPollingInterval : 5000; 157 options.alarmsPollingInterval : 5000;
  158 + this.alarmsMaxCountLoad = isDefined(options.alarmsMaxCountLoad) ?
  159 + options.alarmsMaxCountLoad : 0;
  160 + this.alarmsFetchSize = isDefined(options.alarmsFetchSize) ?
  161 + options.alarmsFetchSize : 100;
156 this.alarmSourceListener = null; 162 this.alarmSourceListener = null;
157 this.alarms = []; 163 this.alarms = [];
158 this.originalTimewindow = null; 164 this.originalTimewindow = null;
@@ -712,6 +718,8 @@ export class WidgetSubscription implements IWidgetSubscription { @@ -712,6 +718,8 @@ export class WidgetSubscription implements IWidgetSubscription {
712 alarmSource: this.alarmSource, 718 alarmSource: this.alarmSource,
713 alarmSearchStatus: this.alarmSearchStatus, 719 alarmSearchStatus: this.alarmSearchStatus,
714 alarmsPollingInterval: this.alarmsPollingInterval, 720 alarmsPollingInterval: this.alarmsPollingInterval,
  721 + alarmsMaxCountLoad: this.alarmsMaxCountLoad,
  722 + alarmsFetchSize: this.alarmsFetchSize,
715 alarmsUpdated: alarms => this.alarmsUpdated(alarms) 723 alarmsUpdated: alarms => this.alarmsUpdated(alarms)
716 }; 724 };
717 this.alarms = null; 725 this.alarms = null;
@@ -38,12 +38,15 @@ import { Direction, SortOrder } from '@shared/models/page/sort-order'; @@ -38,12 +38,15 @@ import { Direction, SortOrder } from '@shared/models/page/sort-order';
38 import { concatMap, expand, map, toArray } from 'rxjs/operators'; 38 import { concatMap, expand, map, toArray } from 'rxjs/operators';
39 import { EMPTY } from 'rxjs'; 39 import { EMPTY } from 'rxjs';
40 import Timeout = NodeJS.Timeout; 40 import Timeout = NodeJS.Timeout;
  41 +import { isDefined } from '@core/utils';
41 42
42 interface AlarmSourceListenerQuery { 43 interface AlarmSourceListenerQuery {
43 entityType: EntityType; 44 entityType: EntityType;
44 entityId: string; 45 entityId: string;
45 alarmSearchStatus: AlarmSearchStatus; 46 alarmSearchStatus: AlarmSearchStatus;
46 alarmStatus: AlarmStatus; 47 alarmStatus: AlarmStatus;
  48 + alarmsMaxCountLoad: number;
  49 + alarmsFetchSize: number;
47 fetchOriginator?: boolean; 50 fetchOriginator?: boolean;
48 limit?: number; 51 limit?: number;
49 interval?: number; 52 interval?: number;
@@ -58,6 +61,8 @@ export interface AlarmSourceListener { @@ -58,6 +61,8 @@ export interface AlarmSourceListener {
58 alarmSource: Datasource; 61 alarmSource: Datasource;
59 alarmsPollingInterval: number; 62 alarmsPollingInterval: number;
60 alarmSearchStatus: AlarmSearchStatus; 63 alarmSearchStatus: AlarmSearchStatus;
  64 + alarmsMaxCountLoad: number;
  65 + alarmsFetchSize: number;
61 alarmsUpdated: (alarms: Array<AlarmInfo>) => void; 66 alarmsUpdated: (alarms: Array<AlarmInfo>) => void;
62 lastUpdateTs?: number; 67 lastUpdateTs?: number;
63 alarmsQuery?: AlarmSourceListenerQuery; 68 alarmsQuery?: AlarmSourceListenerQuery;
@@ -132,7 +137,9 @@ export class AlarmService { @@ -132,7 +137,9 @@ export class AlarmService {
132 entityType: alarmSource.entityType, 137 entityType: alarmSource.entityType,
133 entityId: alarmSource.entityId, 138 entityId: alarmSource.entityId,
134 alarmSearchStatus: alarmSourceListener.alarmSearchStatus, 139 alarmSearchStatus: alarmSourceListener.alarmSearchStatus,
135 - alarmStatus: null 140 + alarmStatus: null,
  141 + alarmsMaxCountLoad: alarmSourceListener.alarmsMaxCountLoad,
  142 + alarmsFetchSize: alarmSourceListener.alarmsFetchSize
136 }; 143 };
137 const originatorKeys = alarmSource.dataKeys.filter(dataKey => dataKey.name.toLocaleLowerCase().includes('originator')); 144 const originatorKeys = alarmSource.dataKeys.filter(dataKey => dataKey.name.toLocaleLowerCase().includes('originator'));
138 if (originatorKeys.length) { 145 if (originatorKeys.length) {
@@ -186,32 +193,49 @@ export class AlarmService { @@ -186,32 +193,49 @@ export class AlarmService {
186 null, 193 null,
187 sortOrder); 194 sortOrder);
188 } else if (alarmsQuery.interval) { 195 } else if (alarmsQuery.interval) {
189 - pageLink = new TimePageLink(100, 0, 196 + pageLink = new TimePageLink(alarmsQuery.alarmsFetchSize || 100, 0,
190 null, 197 null,
191 sortOrder, time - alarmsQuery.interval); 198 sortOrder, time - alarmsQuery.interval);
192 } else if (alarmsQuery.startTime) { 199 } else if (alarmsQuery.startTime) {
193 - pageLink = new TimePageLink(100, 0, 200 + pageLink = new TimePageLink(alarmsQuery.alarmsFetchSize || 100, 0,
194 null, 201 null,
195 sortOrder, Math.round(alarmsQuery.startTime)); 202 sortOrder, Math.round(alarmsQuery.startTime));
196 if (alarmsQuery.endTime) { 203 if (alarmsQuery.endTime) {
197 pageLink.endTime = Math.round(alarmsQuery.endTime); 204 pageLink.endTime = Math.round(alarmsQuery.endTime);
198 } 205 }
199 } 206 }
200 - return this.fetchAlarms(alarmsQuery, pageLink); 207 + let leftToLoad;
  208 + if (isDefined(alarmsQuery.alarmsMaxCountLoad) && alarmsQuery.alarmsMaxCountLoad !== 0) {
  209 + leftToLoad = alarmsQuery.alarmsMaxCountLoad;
  210 + if (leftToLoad < pageLink.pageSize) {
  211 + pageLink.pageSize = leftToLoad;
  212 + }
  213 + }
  214 + return this.fetchAlarms(alarmsQuery, pageLink, leftToLoad);
201 } 215 }
202 216
203 private fetchAlarms(query: AlarmSourceListenerQuery, 217 private fetchAlarms(query: AlarmSourceListenerQuery,
204 - pageLink: TimePageLink): Observable<Array<AlarmInfo>> { 218 + pageLink: TimePageLink, leftToLoad?: number): Observable<Array<AlarmInfo>> {
205 const alarmQuery = new AlarmQuery( 219 const alarmQuery = new AlarmQuery(
206 {id: query.entityId, entityType: query.entityType}, 220 {id: query.entityId, entityType: query.entityType},
207 pageLink, 221 pageLink,
208 query.alarmSearchStatus, 222 query.alarmSearchStatus,
209 query.alarmStatus, 223 query.alarmStatus,
210 - query.fetchOriginator); 224 + query.fetchOriginator,
  225 + null);
211 return this.getAlarms(alarmQuery, {ignoreLoading: true}).pipe( 226 return this.getAlarms(alarmQuery, {ignoreLoading: true}).pipe(
212 expand((data) => { 227 expand((data) => {
213 - if (data.hasNext && !query.limit) {  
214 - alarmQuery.pageLink.page += 1; 228 + let continueLoad = data.hasNext && !query.limit;
  229 + if (continueLoad && isDefined(leftToLoad)) {
  230 + leftToLoad -= data.data.length;
  231 + if (leftToLoad === 0) {
  232 + continueLoad = false;
  233 + } else if (leftToLoad < alarmQuery.pageLink.pageSize) {
  234 + alarmQuery.pageLink.pageSize = leftToLoad;
  235 + }
  236 + }
  237 + if (continueLoad) {
  238 + alarmQuery.offset = data.data[data.data.length-1].id.id;
215 return this.getAlarms(alarmQuery, {ignoreLoading: true}); 239 return this.getAlarms(alarmQuery, {ignoreLoading: true});
216 } else { 240 } else {
217 return EMPTY; 241 return EMPTY;
@@ -110,7 +110,7 @@ export class AlarmTableConfig extends EntityTableConfig<AlarmInfo, TimePageLink> @@ -110,7 +110,7 @@ export class AlarmTableConfig extends EntityTableConfig<AlarmInfo, TimePageLink>
110 } 110 }
111 111
112 fetchAlarms(pageLink: TimePageLink): Observable<PageData<AlarmInfo>> { 112 fetchAlarms(pageLink: TimePageLink): Observable<PageData<AlarmInfo>> {
113 - const query = new AlarmQuery(this.entityId, pageLink, this.searchStatus, null, true); 113 + const query = new AlarmQuery(this.entityId, pageLink, this.searchStatus, null, true, null);
114 return this.alarmService.getAlarms(query); 114 return this.alarmService.getAlarms(query);
115 } 115 }
116 116
@@ -36,29 +36,60 @@ @@ -36,29 +36,60 @@
36 fxFlex formControlName="timewindow"></tb-timewindow> 36 fxFlex formControlName="timewindow"></tb-timewindow>
37 </section> 37 </section>
38 </div> 38 </div>
39 - <div *ngIf="widgetType === widgetTypes.alarm" fxLayout="column" fxLayoutGap="8px" fxLayoutAlign="center"  
40 - fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center">  
41 - <mat-form-field fxFlex class="mat-block">  
42 - <mat-label translate>alarm.alarm-status</mat-label>  
43 - <mat-select matInput formControlName="alarmSearchStatus">  
44 - <mat-option *ngFor="let searchStatus of alarmSearchStatuses" [value]="searchStatus">  
45 - {{ ('alarm.search-status.' + searchStatus) | translate }}  
46 - </mat-option>  
47 - </mat-select>  
48 - </mat-form-field>  
49 - <mat-form-field fxFlex class="mat-block">  
50 - <mat-label translate>alarm.polling-interval</mat-label>  
51 - <input matInput required  
52 - formControlName="alarmsPollingInterval"  
53 - type="number"  
54 - step="1"/>  
55 - <mat-error *ngIf="dataSettings.get('alarmsPollingInterval').hasError('required')">  
56 - {{ 'alarm.polling-interval-required' | translate }}  
57 - </mat-error>  
58 - <mat-error *ngIf="dataSettings.get('alarmsPollingInterval').hasError('min')">  
59 - {{ 'alarm.min-polling-interval-message' | translate }}  
60 - </mat-error>  
61 - </mat-form-field> 39 + <div *ngIf="widgetType === widgetTypes.alarm" fxLayout="column" fxLayoutAlign="center">
  40 + <div fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center" fxLayoutGap="8px">
  41 + <mat-form-field fxFlex class="mat-block">
  42 + <mat-label translate>alarm.alarm-status</mat-label>
  43 + <mat-select matInput formControlName="alarmSearchStatus">
  44 + <mat-option *ngFor="let searchStatus of alarmSearchStatuses" [value]="searchStatus">
  45 + {{ ('alarm.search-status.' + searchStatus) | translate }}
  46 + </mat-option>
  47 + </mat-select>
  48 + </mat-form-field>
  49 + <mat-form-field fxFlex class="mat-block">
  50 + <mat-label translate>alarm.polling-interval</mat-label>
  51 + <input matInput required
  52 + formControlName="alarmsPollingInterval"
  53 + type="number"
  54 + step="1"/>
  55 + <mat-error *ngIf="dataSettings.get('alarmsPollingInterval').hasError('required')">
  56 + {{ 'alarm.polling-interval-required' | translate }}
  57 + </mat-error>
  58 + <mat-error *ngIf="dataSettings.get('alarmsPollingInterval').hasError('min')">
  59 + {{ 'alarm.min-polling-interval-message' | translate }}
  60 + </mat-error>
  61 + </mat-form-field>
  62 + </div>
  63 + <div fxLayout.gt-sm="row" fxLayoutAlign.gt-sm="start center" fxLayoutGap="8px">
  64 + <mat-form-field fxFlex class="mat-block">
  65 + <mat-label translate>alarm.max-count-load</mat-label>
  66 + <input matInput required
  67 + formControlName="alarmsMaxCountLoad"
  68 + type="number"
  69 + min="0"
  70 + step="1">
  71 + <mat-error *ngIf="dataSettings.get('alarmsMaxCountLoad').hasError('required')">
  72 + {{ 'alarm.max-count-load-required' | translate }}
  73 + </mat-error>
  74 + <mat-error *ngIf="dataSettings.get('alarmsMaxCountLoad').hasError('min')">
  75 + {{ 'alarm.max-count-load-error-min' | translate }}
  76 + </mat-error>
  77 + </mat-form-field>
  78 + <mat-form-field fxFlex class="mat-block">
  79 + <mat-label translate>alarm.fetch-size</mat-label>
  80 + <input matInput required
  81 + formControlName="alarmsFetchSize"
  82 + type="number"
  83 + min="10"
  84 + step="1">
  85 + <mat-error *ngIf="dataSettings.get('alarmsFetchSize').hasError('required')">
  86 + {{ 'alarm.fetch-size-required' | translate }}
  87 + </mat-error>
  88 + <mat-error *ngIf="dataSettings.get('alarmsFetchSize').hasError('min')">
  89 + {{ 'alarm.fetch-size-error-min' | translate }}
  90 + </mat-error>
  91 + </mat-form-field>
  92 + </div>
62 </div> 93 </div>
63 <mat-expansion-panel class="tb-datasources" *ngIf="widgetType !== widgetTypes.rpc && 94 <mat-expansion-panel class="tb-datasources" *ngIf="widgetType !== widgetTypes.rpc &&
64 widgetType !== widgetTypes.alarm && 95 widgetType !== widgetTypes.alarm &&
@@ -287,6 +287,10 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont @@ -287,6 +287,10 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont
287 this.dataSettings.addControl('alarmSearchStatus', this.fb.control(null)); 287 this.dataSettings.addControl('alarmSearchStatus', this.fb.control(null));
288 this.dataSettings.addControl('alarmsPollingInterval', this.fb.control(null, 288 this.dataSettings.addControl('alarmsPollingInterval', this.fb.control(null,
289 [Validators.required, Validators.min(1)])); 289 [Validators.required, Validators.min(1)]));
  290 + this.dataSettings.addControl('alarmsMaxCountLoad', this.fb.control(null,
  291 + [Validators.required, Validators.min(0)]));
  292 + this.dataSettings.addControl('alarmsFetchSize', this.fb.control(null,
  293 + [Validators.required, Validators.min(10)]));
290 } 294 }
291 } 295 }
292 if (this.modelValue.isDataEnabled) { 296 if (this.modelValue.isDataEnabled) {
@@ -439,6 +443,14 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont @@ -439,6 +443,14 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont
439 { alarmsPollingInterval: isDefined(config.alarmsPollingInterval) ? 443 { alarmsPollingInterval: isDefined(config.alarmsPollingInterval) ?
440 config.alarmsPollingInterval : 5}, {emitEvent: false} 444 config.alarmsPollingInterval : 5}, {emitEvent: false}
441 ); 445 );
  446 + this.dataSettings.patchValue(
  447 + { alarmsMaxCountLoad: isDefined(config.alarmsMaxCountLoad) ?
  448 + config.alarmsMaxCountLoad : 0}, {emitEvent: false}
  449 + );
  450 + this.dataSettings.patchValue(
  451 + { alarmsFetchSize: isDefined(config.alarmsFetchSize) ?
  452 + config.alarmsFetchSize : 100}, {emitEvent: false}
  453 + );
442 this.alarmSourceSettings.patchValue( 454 this.alarmSourceSettings.patchValue(
443 config.alarmSource, {emitEvent: false} 455 config.alarmSource, {emitEvent: false}
444 ); 456 );
@@ -828,6 +828,10 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI @@ -828,6 +828,10 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI
828 this.widget.config.alarmSearchStatus : AlarmSearchStatus.ANY; 828 this.widget.config.alarmSearchStatus : AlarmSearchStatus.ANY;
829 options.alarmsPollingInterval = isDefined(this.widget.config.alarmsPollingInterval) ? 829 options.alarmsPollingInterval = isDefined(this.widget.config.alarmsPollingInterval) ?
830 this.widget.config.alarmsPollingInterval * 1000 : 5000; 830 this.widget.config.alarmsPollingInterval * 1000 : 5000;
  831 + options.alarmsMaxCountLoad = isDefined(this.widget.config.alarmsMaxCountLoad) ?
  832 + this.widget.config.alarmsMaxCountLoad : 0;
  833 + options.alarmsFetchSize = isDefined(this.widget.config.alarmsFetchSize) ?
  834 + this.widget.config.alarmsFetchSize : 100;
831 } else { 835 } else {
832 options.datasources = deepClone(this.widget.config.datasources); 836 options.datasources = deepClone(this.widget.config.datasources);
833 } 837 }
@@ -14,16 +14,14 @@ @@ -14,16 +14,14 @@
14 /// limitations under the License. 14 /// limitations under the License.
15 /// 15 ///
16 16
17 -import {BaseData} from '@shared/models/base-data';  
18 -import {AssetId} from '@shared/models/id/asset-id';  
19 -import {TenantId} from '@shared/models/id/tenant-id';  
20 -import {CustomerId} from '@shared/models/id/customer-id';  
21 -import {AlarmId} from '@shared/models/id/alarm-id';  
22 -import {EntityId} from '@shared/models/id/entity-id';  
23 -import { ActionStatus } from '@shared/models/audit-log.models'; 17 +import { BaseData } from '@shared/models/base-data';
  18 +import { TenantId } from '@shared/models/id/tenant-id';
  19 +import { AlarmId } from '@shared/models/id/alarm-id';
  20 +import { EntityId } from '@shared/models/id/entity-id';
24 import { TimePageLink } from '@shared/models/page/page-link'; 21 import { TimePageLink } from '@shared/models/page/page-link';
25 import { NULL_UUID } from '@shared/models/id/has-uuid'; 22 import { NULL_UUID } from '@shared/models/id/has-uuid';
26 import { EntityType } from '@shared/models/entity-type.models'; 23 import { EntityType } from '@shared/models/entity-type.models';
  24 +import { isString } from '@core/utils';
27 25
28 export enum AlarmSeverity { 26 export enum AlarmSeverity {
29 CRITICAL = 'CRITICAL', 27 CRITICAL = 'CRITICAL',
@@ -199,15 +197,17 @@ export class AlarmQuery { @@ -199,15 +197,17 @@ export class AlarmQuery {
199 searchStatus: AlarmSearchStatus; 197 searchStatus: AlarmSearchStatus;
200 status: AlarmStatus; 198 status: AlarmStatus;
201 fetchOriginator: boolean; 199 fetchOriginator: boolean;
  200 + offset: string;
202 201
203 constructor(entityId: EntityId, pageLink: TimePageLink, 202 constructor(entityId: EntityId, pageLink: TimePageLink,
204 searchStatus: AlarmSearchStatus, status: AlarmStatus, 203 searchStatus: AlarmSearchStatus, status: AlarmStatus,
205 - fetchOriginator: boolean) { 204 + fetchOriginator: boolean, offset: string) {
206 this.affectedEntityId = entityId; 205 this.affectedEntityId = entityId;
207 this.pageLink = pageLink; 206 this.pageLink = pageLink;
208 this.searchStatus = searchStatus; 207 this.searchStatus = searchStatus;
209 this.status = status; 208 this.status = status;
210 this.fetchOriginator = fetchOriginator; 209 this.fetchOriginator = fetchOriginator;
  210 + this.offset = offset;
211 } 211 }
212 212
213 public toQuery(): string { 213 public toQuery(): string {
@@ -221,6 +221,9 @@ export class AlarmQuery { @@ -221,6 +221,9 @@ export class AlarmQuery {
221 if (typeof this.fetchOriginator !== 'undefined' && this.fetchOriginator !== null) { 221 if (typeof this.fetchOriginator !== 'undefined' && this.fetchOriginator !== null) {
222 query += `&fetchOriginator=${this.fetchOriginator}`; 222 query += `&fetchOriginator=${this.fetchOriginator}`;
223 } 223 }
  224 + if (isString(this.offset) && this.offset.length) {
  225 + query += `&offset=${this.offset}`;
  226 + }
224 return query; 227 return query;
225 } 228 }
226 229
@@ -360,6 +360,8 @@ export interface WidgetConfig { @@ -360,6 +360,8 @@ export interface WidgetConfig {
360 alarmSource?: Datasource; 360 alarmSource?: Datasource;
361 alarmSearchStatus?: AlarmSearchStatus; 361 alarmSearchStatus?: AlarmSearchStatus;
362 alarmsPollingInterval?: number; 362 alarmsPollingInterval?: number;
  363 + alarmsMaxCountLoad?: number;
  364 + alarmsFetchSize?: number;
363 datasources?: Array<Datasource>; 365 datasources?: Array<Datasource>;
364 targetDeviceAliasIds?: Array<string>; 366 targetDeviceAliasIds?: Array<string>;
365 [key: string]: any; 367 [key: string]: any;