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,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; |