Commit 620b66b7008abfacb9f15b7bb4a699e4834c864e
Merge branch 'develop/3.0' of github.com:thingsboard/thingsboard into develop/3.0
Showing
14 changed files
with
142 additions
and
43 deletions
... | ... | @@ -44,6 +44,8 @@ import org.thingsboard.server.common.data.page.TimePageLink; |
44 | 44 | import org.thingsboard.server.service.security.permission.Operation; |
45 | 45 | import org.thingsboard.server.service.security.permission.Resource; |
46 | 46 | |
47 | +import java.util.UUID; | |
48 | + | |
47 | 49 | @RestController |
48 | 50 | @RequestMapping("/api") |
49 | 51 | public class AlarmController extends BaseController { |
... | ... | @@ -155,6 +157,7 @@ public class AlarmController extends BaseController { |
155 | 157 | @RequestParam(required = false) String sortOrder, |
156 | 158 | @RequestParam(required = false) Long startTime, |
157 | 159 | @RequestParam(required = false) Long endTime, |
160 | + @RequestParam(required = false) String offset, | |
158 | 161 | @RequestParam(required = false) Boolean fetchOriginator |
159 | 162 | ) throws ThingsboardException { |
160 | 163 | checkParameter("EntityId", strEntityId); |
... | ... | @@ -168,8 +171,12 @@ public class AlarmController extends BaseController { |
168 | 171 | } |
169 | 172 | checkEntityId(entityId, Operation.READ); |
170 | 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 | 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 | 180 | } catch (Exception e) { |
174 | 181 | throw handleException(e); |
175 | 182 | } | ... | ... |
... | ... | @@ -22,6 +22,8 @@ import org.thingsboard.server.common.data.id.EntityId; |
22 | 22 | import org.thingsboard.server.common.data.id.TenantId; |
23 | 23 | import org.thingsboard.server.common.data.page.TimePageLink; |
24 | 24 | |
25 | +import java.util.UUID; | |
26 | + | |
25 | 27 | /** |
26 | 28 | * Created by ashvayka on 11.05.17. |
27 | 29 | */ |
... | ... | @@ -35,5 +37,6 @@ public class AlarmQuery { |
35 | 37 | private AlarmSearchStatus searchStatus; |
36 | 38 | private AlarmStatus status; |
37 | 39 | private Boolean fetchOriginator; |
40 | + private UUID idOffset; | |
38 | 41 | |
39 | 42 | } | ... | ... |
... | ... | @@ -300,7 +300,7 @@ public class BaseAlarmService extends AbstractEntityService implements AlarmServ |
300 | 300 | AlarmSeverity highestSeverity = null; |
301 | 301 | AlarmQuery query; |
302 | 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 | 304 | PageData<AlarmInfo> alarms = alarmDao.findAlarms(tenantId, query); |
305 | 305 | if (alarms.hasNext()) { |
306 | 306 | nextPageLink = nextPageLink.nextPageLink(); | ... | ... |
... | ... | @@ -33,7 +33,7 @@ import java.util.List; |
33 | 33 | @SqlDao |
34 | 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 | 37 | List<AlarmEntity> findLatestByOriginatorAndType(@Param("originatorId") String originatorId, |
38 | 38 | @Param("alarmType") String alarmType, |
39 | 39 | Pageable pageable); |
... | ... | @@ -48,6 +48,7 @@ public interface AlarmRepository extends CrudRepository<AlarmEntity, String> { |
48 | 48 | "AND re.fromType = :affectedEntityType " + |
49 | 49 | "AND (:startId IS NULL OR a.id >= :startId) " + |
50 | 50 | "AND (:endId IS NULL OR a.id <= :endId) " + |
51 | + "AND (:idOffset IS NULL OR a.id < :idOffset) " + | |
51 | 52 | "AND (LOWER(a.type) LIKE LOWER(CONCAT(:searchText, '%'))" + |
52 | 53 | "OR LOWER(a.severity) LIKE LOWER(CONCAT(:searchText, '%'))" + |
53 | 54 | "OR LOWER(a.status) LIKE LOWER(CONCAT(:searchText, '%')))") |
... | ... | @@ -57,6 +58,7 @@ public interface AlarmRepository extends CrudRepository<AlarmEntity, String> { |
57 | 58 | @Param("relationType") String relationType, |
58 | 59 | @Param("startId") String startId, |
59 | 60 | @Param("endId") String endId, |
61 | + @Param("idOffset") String idOffset, | |
60 | 62 | @Param("searchText") String searchText, |
61 | 63 | Pageable pageable); |
62 | 64 | } | ... | ... |
... | ... | @@ -117,6 +117,7 @@ public class JpaAlarmDao extends JpaAbstractDao<AlarmEntity, Alarm> implements A |
117 | 117 | relationType, |
118 | 118 | startTimeToId(query.getPageLink().getStartTime()), |
119 | 119 | endTimeToId(query.getPageLink().getEndTime()), |
120 | + query.getIdOffset() != null ? UUIDConverter.fromTimeUUID(query.getIdOffset()) : null, | |
120 | 121 | Objects.toString(query.getPageLink().getTextSearch(), ""), |
121 | 122 | DaoUtil.toPageable(query.getPageLink()) |
122 | 123 | ) | ... | ... |
... | ... | @@ -190,6 +190,8 @@ export interface WidgetSubscriptionOptions { |
190 | 190 | alarmSource?: Datasource; |
191 | 191 | alarmSearchStatus?: AlarmSearchStatus; |
192 | 192 | alarmsPollingInterval?: number; |
193 | + alarmsMaxCountLoad?: number; | |
194 | + alarmsFetchSize?: number; | |
193 | 195 | datasources?: Array<Datasource>; |
194 | 196 | targetDeviceAliasIds?: Array<string>; |
195 | 197 | targetDeviceIds?: Array<string>; | ... | ... |
... | ... | @@ -93,6 +93,8 @@ export class WidgetSubscription implements IWidgetSubscription { |
93 | 93 | } |
94 | 94 | |
95 | 95 | alarmsPollingInterval: number; |
96 | + alarmsMaxCountLoad: number; | |
97 | + alarmsFetchSize: number; | |
96 | 98 | alarmSourceListener: AlarmSourceListener; |
97 | 99 | |
98 | 100 | loadingData: boolean; |
... | ... | @@ -153,6 +155,10 @@ export class WidgetSubscription implements IWidgetSubscription { |
153 | 155 | options.alarmSearchStatus : AlarmSearchStatus.ANY; |
154 | 156 | this.alarmsPollingInterval = isDefined(options.alarmsPollingInterval) ? |
155 | 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 | 162 | this.alarmSourceListener = null; |
157 | 163 | this.alarms = []; |
158 | 164 | this.originalTimewindow = null; |
... | ... | @@ -712,6 +718,8 @@ export class WidgetSubscription implements IWidgetSubscription { |
712 | 718 | alarmSource: this.alarmSource, |
713 | 719 | alarmSearchStatus: this.alarmSearchStatus, |
714 | 720 | alarmsPollingInterval: this.alarmsPollingInterval, |
721 | + alarmsMaxCountLoad: this.alarmsMaxCountLoad, | |
722 | + alarmsFetchSize: this.alarmsFetchSize, | |
715 | 723 | alarmsUpdated: alarms => this.alarmsUpdated(alarms) |
716 | 724 | }; |
717 | 725 | this.alarms = null; | ... | ... |
... | ... | @@ -38,12 +38,15 @@ import { Direction, SortOrder } from '@shared/models/page/sort-order'; |
38 | 38 | import { concatMap, expand, map, toArray } from 'rxjs/operators'; |
39 | 39 | import { EMPTY } from 'rxjs'; |
40 | 40 | import Timeout = NodeJS.Timeout; |
41 | +import { isDefined } from '@core/utils'; | |
41 | 42 | |
42 | 43 | interface AlarmSourceListenerQuery { |
43 | 44 | entityType: EntityType; |
44 | 45 | entityId: string; |
45 | 46 | alarmSearchStatus: AlarmSearchStatus; |
46 | 47 | alarmStatus: AlarmStatus; |
48 | + alarmsMaxCountLoad: number; | |
49 | + alarmsFetchSize: number; | |
47 | 50 | fetchOriginator?: boolean; |
48 | 51 | limit?: number; |
49 | 52 | interval?: number; |
... | ... | @@ -58,6 +61,8 @@ export interface AlarmSourceListener { |
58 | 61 | alarmSource: Datasource; |
59 | 62 | alarmsPollingInterval: number; |
60 | 63 | alarmSearchStatus: AlarmSearchStatus; |
64 | + alarmsMaxCountLoad: number; | |
65 | + alarmsFetchSize: number; | |
61 | 66 | alarmsUpdated: (alarms: Array<AlarmInfo>) => void; |
62 | 67 | lastUpdateTs?: number; |
63 | 68 | alarmsQuery?: AlarmSourceListenerQuery; |
... | ... | @@ -132,7 +137,9 @@ export class AlarmService { |
132 | 137 | entityType: alarmSource.entityType, |
133 | 138 | entityId: alarmSource.entityId, |
134 | 139 | alarmSearchStatus: alarmSourceListener.alarmSearchStatus, |
135 | - alarmStatus: null | |
140 | + alarmStatus: null, | |
141 | + alarmsMaxCountLoad: alarmSourceListener.alarmsMaxCountLoad, | |
142 | + alarmsFetchSize: alarmSourceListener.alarmsFetchSize | |
136 | 143 | }; |
137 | 144 | const originatorKeys = alarmSource.dataKeys.filter(dataKey => dataKey.name.toLocaleLowerCase().includes('originator')); |
138 | 145 | if (originatorKeys.length) { |
... | ... | @@ -186,32 +193,49 @@ export class AlarmService { |
186 | 193 | null, |
187 | 194 | sortOrder); |
188 | 195 | } else if (alarmsQuery.interval) { |
189 | - pageLink = new TimePageLink(100, 0, | |
196 | + pageLink = new TimePageLink(alarmsQuery.alarmsFetchSize || 100, 0, | |
190 | 197 | null, |
191 | 198 | sortOrder, time - alarmsQuery.interval); |
192 | 199 | } else if (alarmsQuery.startTime) { |
193 | - pageLink = new TimePageLink(100, 0, | |
200 | + pageLink = new TimePageLink(alarmsQuery.alarmsFetchSize || 100, 0, | |
194 | 201 | null, |
195 | 202 | sortOrder, Math.round(alarmsQuery.startTime)); |
196 | 203 | if (alarmsQuery.endTime) { |
197 | 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 | 217 | private fetchAlarms(query: AlarmSourceListenerQuery, |
204 | - pageLink: TimePageLink): Observable<Array<AlarmInfo>> { | |
218 | + pageLink: TimePageLink, leftToLoad?: number): Observable<Array<AlarmInfo>> { | |
205 | 219 | const alarmQuery = new AlarmQuery( |
206 | 220 | {id: query.entityId, entityType: query.entityType}, |
207 | 221 | pageLink, |
208 | 222 | query.alarmSearchStatus, |
209 | 223 | query.alarmStatus, |
210 | - query.fetchOriginator); | |
224 | + query.fetchOriginator, | |
225 | + null); | |
211 | 226 | return this.getAlarms(alarmQuery, {ignoreLoading: true}).pipe( |
212 | 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 | 239 | return this.getAlarms(alarmQuery, {ignoreLoading: true}); |
216 | 240 | } else { |
217 | 241 | return EMPTY; | ... | ... |
... | ... | @@ -110,7 +110,7 @@ export class AlarmTableConfig extends EntityTableConfig<AlarmInfo, TimePageLink> |
110 | 110 | } |
111 | 111 | |
112 | 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 | 114 | return this.alarmService.getAlarms(query); |
115 | 115 | } |
116 | 116 | ... | ... |
... | ... | @@ -36,29 +36,60 @@ |
36 | 36 | fxFlex formControlName="timewindow"></tb-timewindow> |
37 | 37 | </section> |
38 | 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 | 93 | </div> |
63 | 94 | <mat-expansion-panel class="tb-datasources" *ngIf="widgetType !== widgetTypes.rpc && |
64 | 95 | widgetType !== widgetTypes.alarm && | ... | ... |
... | ... | @@ -287,6 +287,10 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont |
287 | 287 | this.dataSettings.addControl('alarmSearchStatus', this.fb.control(null)); |
288 | 288 | this.dataSettings.addControl('alarmsPollingInterval', this.fb.control(null, |
289 | 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 | 296 | if (this.modelValue.isDataEnabled) { |
... | ... | @@ -439,6 +443,14 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, Cont |
439 | 443 | { alarmsPollingInterval: isDefined(config.alarmsPollingInterval) ? |
440 | 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 | 454 | this.alarmSourceSettings.patchValue( |
443 | 455 | config.alarmSource, {emitEvent: false} |
444 | 456 | ); | ... | ... |
... | ... | @@ -828,6 +828,10 @@ export class WidgetComponent extends PageComponent implements OnInit, AfterViewI |
828 | 828 | this.widget.config.alarmSearchStatus : AlarmSearchStatus.ANY; |
829 | 829 | options.alarmsPollingInterval = isDefined(this.widget.config.alarmsPollingInterval) ? |
830 | 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 | 835 | } else { |
832 | 836 | options.datasources = deepClone(this.widget.config.datasources); |
833 | 837 | } | ... | ... |
... | ... | @@ -14,16 +14,14 @@ |
14 | 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 | 21 | import { TimePageLink } from '@shared/models/page/page-link'; |
25 | 22 | import { NULL_UUID } from '@shared/models/id/has-uuid'; |
26 | 23 | import { EntityType } from '@shared/models/entity-type.models'; |
24 | +import { isString } from '@core/utils'; | |
27 | 25 | |
28 | 26 | export enum AlarmSeverity { |
29 | 27 | CRITICAL = 'CRITICAL', |
... | ... | @@ -199,15 +197,17 @@ export class AlarmQuery { |
199 | 197 | searchStatus: AlarmSearchStatus; |
200 | 198 | status: AlarmStatus; |
201 | 199 | fetchOriginator: boolean; |
200 | + offset: string; | |
202 | 201 | |
203 | 202 | constructor(entityId: EntityId, pageLink: TimePageLink, |
204 | 203 | searchStatus: AlarmSearchStatus, status: AlarmStatus, |
205 | - fetchOriginator: boolean) { | |
204 | + fetchOriginator: boolean, offset: string) { | |
206 | 205 | this.affectedEntityId = entityId; |
207 | 206 | this.pageLink = pageLink; |
208 | 207 | this.searchStatus = searchStatus; |
209 | 208 | this.status = status; |
210 | 209 | this.fetchOriginator = fetchOriginator; |
210 | + this.offset = offset; | |
211 | 211 | } |
212 | 212 | |
213 | 213 | public toQuery(): string { |
... | ... | @@ -221,6 +221,9 @@ export class AlarmQuery { |
221 | 221 | if (typeof this.fetchOriginator !== 'undefined' && this.fetchOriginator !== null) { |
222 | 222 | query += `&fetchOriginator=${this.fetchOriginator}`; |
223 | 223 | } |
224 | + if (isString(this.offset) && this.offset.length) { | |
225 | + query += `&offset=${this.offset}`; | |
226 | + } | |
224 | 227 | return query; |
225 | 228 | } |
226 | 229 | ... | ... |
... | ... | @@ -360,6 +360,8 @@ export interface WidgetConfig { |
360 | 360 | alarmSource?: Datasource; |
361 | 361 | alarmSearchStatus?: AlarmSearchStatus; |
362 | 362 | alarmsPollingInterval?: number; |
363 | + alarmsMaxCountLoad?: number; | |
364 | + alarmsFetchSize?: number; | |
363 | 365 | datasources?: Array<Datasource>; |
364 | 366 | targetDeviceAliasIds?: Array<string>; |
365 | 367 | [key: string]: any; | ... | ... |