Browse Source

UI: Update and refactoring

pull/5629/head
ArtemDzhereleiko 5 years ago
parent
commit
aac4ec07ab
  1. 2
      application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java
  2. 5
      ui-ngx/src/app/core/api/widget-api.models.ts
  3. 41
      ui-ngx/src/app/core/api/widget-subscription.ts
  4. 10
      ui-ngx/src/app/core/http/device.service.ts
  5. 2
      ui-ngx/src/app/modules/common/modules-map.ts
  6. 2
      ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.html
  7. 5
      ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.scss
  8. 32
      ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.ts
  9. 2
      ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.html
  10. 5
      ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.scss
  11. 61
      ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.ts
  12. 2
      ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.html
  13. 1
      ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.scss
  14. 16
      ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.ts
  15. 2
      ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html
  16. 1
      ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.scss
  17. 129
      ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.ts
  18. 2
      ui-ngx/src/app/shared/components/json-object-view.component.html
  19. 2
      ui-ngx/src/app/shared/components/json-object-view.component.ts
  20. 1
      ui-ngx/src/app/shared/models/rpc.models.ts
  21. 2
      ui-ngx/src/app/shared/shared.module.ts
  22. 2
      ui-ngx/src/assets/locale/locale.constant-uk_UA.json

2
application/src/main/java/org/thingsboard/server/controller/RpcV2Controller.java

@ -188,7 +188,7 @@ public class RpcV2Controller extends AbstractRpcController {
@RequestParam(required = false) String sortOrder) throws ThingsboardException {
checkParameter("DeviceId", strDeviceId);
try {
if (rpcStatus.equals(RpcStatus.DELETED)) {
if (rpcStatus != null && rpcStatus.equals(RpcStatus.DELETED)) {
throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "RpcStatus: DELETED");
}

5
ui-ngx/src/app/core/api/widget-api.models.ts

@ -55,8 +55,7 @@ import { TranslateService } from '@ngx-translate/core';
import { AlarmDataService } from '@core/api/alarm-data.service';
import { IDashboardController } from '@home/components/dashboard-page/dashboard-page.models';
import { PopoverPlacement } from '@shared/components/popover.models';
import { PageLink } from '@shared/models/page/page-link';
import { PersistentRpc, RpcStatus } from '@shared/models/rpc.models';
import { PersistentRpc } from '@shared/models/rpc.models';
export interface TimewindowFunctions {
onUpdateTimewindow: (startTimeMs: number, endTimeMs: number, interval?: number) => void;
@ -322,8 +321,6 @@ export interface IWidgetSubscription {
persistentPollingInterval?: number, retries?: number, additionalInfo?: any, requestUUID?: string): Observable<any>;
clearRpcError(): void;
subscribeForPersistentRequests(pageLink: PageLink, keyFileter: RpcStatus): Observable<any>;
subscribe(): void;
subscribeAllForPaginatedData(pageLink: EntityDataPageLink,

41
ui-ngx/src/app/core/api/widget-subscription.ts

@ -70,7 +70,6 @@ import {
import { distinct, filter, map, switchMap, takeUntil } from 'rxjs/operators';
import { AlarmDataListener } from '@core/api/alarm-data.service';
import { RpcStatus } from '@shared/models/rpc.models';
import { PageLink } from '@shared/models/page/page-link';
const moment = moment_;
@ -781,46 +780,6 @@ export class WidgetSubscription implements IWidgetSubscription {
}
}
subscribeForPersistentRequests(pageLink: PageLink, keyFilter: RpcStatus): Observable<any> {
if (!this.rpcEnabled) {
return throwError(new Error('Rpc disabled!'));
} else if (!this.targetDeviceId) {
return throwError(new Error('Target device is not set!'));
}
const rpcSubject: Subject<any> = new Subject<any>();
this.ctx.deviceService.getPersistedRpcRequests(this.targetDeviceId, pageLink, keyFilter).subscribe(
(responseBody) => {
rpcSubject.next(responseBody);
rpcSubject.complete();
},
(rejection: HttpErrorResponse) => {
const index = this.executingSubjects.indexOf(rpcSubject);
if (index >= 0) {
this.executingSubjects.splice( index, 1 );
}
this.executingRpcRequest = this.executingSubjects.length > 0;
this.callbacks.rpcStateChanged(this);
if (!this.executingRpcRequest || rejection.status === 504) {
this.rpcRejection = rejection;
if (rejection.status === 504) {
this.rpcErrorText = 'Request Timeout.';
} else {
this.rpcErrorText = 'Error : ' + rejection.status + ' - ' + rejection.statusText;
const error = this.extractRejectionErrorText(rejection);
if (error) {
this.rpcErrorText += '</br>';
this.rpcErrorText += error;
}
}
this.callbacks.onRpcFailed(this);
}
rpcSubject.error(rejection);
}
);
return rpcSubject.asObservable();
}
private extractRejectionErrorText(rejection: HttpErrorResponse) {
let error = null;
if (rejection.error) {

10
ui-ngx/src/app/core/http/device.service.ts

@ -148,10 +148,12 @@ export class DeviceService {
}
public getPersistedRpcRequests(deviceId: string, pageLink: PageLink,
keyFilter: RpcStatus, config?: RequestConfig): Observable<PageData<PersistentRpc>> {
const rpcStatus = keyFilter ? '&rpcStatus=' + keyFilter : '';
return this.http.get<PageData<PersistentRpc>>(`/api/rpc/persistent/device/${deviceId}${pageLink.toQuery()}${rpcStatus}`,
defaultHttpOptionsFromConfig(config));
rpcStatus?: RpcStatus, config?: RequestConfig): Observable<PageData<PersistentRpc>> {
let url = `/api/rpc/persistent/device/${deviceId}${pageLink.toQuery()}`;
if (rpcStatus && rpcStatus.length) {
url += `&rpcStatus=${rpcStatus}`;
}
return this.http.get<PageData<PersistentRpc>>(url, defaultHttpOptionsFromConfig(config));
}
public findByQuery(query: DeviceSearchQuery,

2
ui-ngx/src/app/modules/common/modules-map.ts

@ -139,6 +139,7 @@ import * as QueueTypeListComponent from '@shared/components/queue/queue-type-lis
import * as RelationTypeAutocompleteComponent from '@shared/components/relation/relation-type-autocomplete.component';
import * as SocialSharePanelComponent from '@shared/components/socialshare-panel.component';
import * as JsonObjectEditComponent from '@shared/components/json-object-edit.component';
import * as JsonObjectViewComponent from '@shared/components/json-object-view.component';
import * as JsonContentComponent from '@shared/components/json-content.component';
import * as JsFuncComponent from '@shared/components/js-func.component';
import * as FabToolbarComponent from '@shared/components/fab-toolbar.component';
@ -420,6 +421,7 @@ class ModulesMap implements IModulesMap {
'@shared/components/relation/relation-type-autocomplete.component': RelationTypeAutocompleteComponent,
'@shared/components/socialshare-panel.component': SocialSharePanelComponent,
'@shared/components/json-object-edit.component': JsonObjectEditComponent,
'@shared/components/json-object-view.component': JsonObjectViewComponent,
'@shared/components/json-content.component': JsonContentComponent,
'@shared/components/js-func.component': JsFuncComponent,
'@shared/components/fab-toolbar.component': FabToolbarComponent,

2
ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.html

@ -32,7 +32,7 @@
<fieldset [disabled]="isLoading$ | async">
<div fxLayout="row" fxLayoutGap="6px">
<mat-slide-toggle fxFlex class="mat-block" formControlName="oneWayElseTwoWay">
{{ 'widgets.persistent-table.message-types.' + persistentFormGroup.get('oneWayElseTwoWay').value | translate }}
{{ rpcMessageTypeText }}
</mat-slide-toggle>
</div>
<div fxLayout="row wrap" fxLayout.xs="column" fxLayoutGap="6px">

5
ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.scss

@ -13,8 +13,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host {
.add-dialog ::ng-deep {
:host ::ng-deep {
.add-dialog {
.params-json-editor,
.additional-json-editor {

32
ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-add-dialog.component.ts

@ -22,6 +22,7 @@ import { Router } from '@angular/router';
import { MatDialogRef } from '@angular/material/dialog';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { RequestData } from '@shared/models/rpc.models';
import { TranslateService } from '@ngx-translate/core';
@Component({
selector: 'tb-persistent-add-dialog',
@ -32,15 +33,15 @@ import { RequestData } from '@shared/models/rpc.models';
export class PersistentAddDialogComponent extends DialogComponent<PersistentAddDialogComponent, RequestData> implements OnInit {
public persistentFormGroup: FormGroup;
public rpcMessageTypeText: string;
private requestData: RequestData = {
persistentUpdated: false
};
private requestData: RequestData = null;
constructor(protected store: Store<AppState>,
protected router: Router,
public dialogRef: MatDialogRef<PersistentAddDialogComponent, RequestData>,
private fb: FormBuilder) {
private fb: FormBuilder,
private translate: TranslateService) {
super(store, router, dialogRef);
this.persistentFormGroup = this.fb.group(
@ -48,27 +49,24 @@ export class PersistentAddDialogComponent extends DialogComponent<PersistentAddD
method: ['', [Validators.required, Validators.pattern(/^\S+$/)]],
oneWayElseTwoWay: [false],
retries: [null, [Validators.pattern(/^-?[0-9]+$/), Validators.min(0)]],
params: [{}],
additionalInfo: [{}]
params: [null],
additionalInfo: [null]
}
);
}
save() {
if (this.persistentFormGroup.valid) {
this.requestData = {
persistentUpdated: true,
method: this.persistentFormGroup.get('method').value,
oneWayElseTwoWay: this.persistentFormGroup.get('oneWayElseTwoWay').value,
params: this.persistentFormGroup.get('params').value,
additionalInfo: this.persistentFormGroup.get('additionalInfo').value,
retries: this.persistentFormGroup.get('retries').value
};
this.close();
}
this.requestData = this.persistentFormGroup.value;
this.close();
}
ngOnInit(): void {
this.rpcMessageTypeText = this.translate.instant('widgets.persistent-table.message-types.false');
this.persistentFormGroup.get('oneWayElseTwoWay').valueChanges.subscribe(
() => {
this.rpcMessageTypeText = this.translate.instant(`widgets.persistent-table.message-types.${this.persistentFormGroup.get('oneWayElseTwoWay').value}`);
}
);
}
close(): void {

2
ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.html

@ -48,7 +48,7 @@
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.persistent-table.status</mat-label>
<input matInput formControlName="status" readonly
[ngStyle]="{fontWeight: 'bold', color: rpcStatusColorsMap.get((data.persistentRequest.status))}">
[ngStyle]="{ fontWeight: 'bold', color: rpcStatusColorsMap.get(data.persistentRequest.status) }">
</mat-form-field>
<mat-form-field fxFlex class="mat-block">
<mat-label translate>widgets.persistent-table.method</mat-label>

5
ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.scss

@ -13,8 +13,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host {
.rpc-dialog ::ng-deep {
:host ::ng-deep {
.rpc-dialog {
.mat-expansion-panel-body {
padding-bottom: 0 !important;
}
@ -23,6 +23,7 @@
margin: 0 0 16px 0;
}
}
.tb-audit-log-response-data {
width: 100%;
min-width: 400px;

61
ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-details-dialog.component.ts

@ -24,13 +24,7 @@ import { TranslateService } from '@ngx-translate/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { FormBuilder, FormGroup } from '@angular/forms';
import { DeviceService } from '@core/http/device.service';
import {
PersistentRpc,
rpcStatusColors,
RpcStatus,
rpcStatusTranslation
} from '@shared/models/rpc.models';
import { isDefinedAndNotNull } from '@core/utils';
import { PersistentRpc, RpcStatus, rpcStatusColors, rpcStatusTranslation } from '@shared/models/rpc.models';
import { NULL_UUID } from '@shared/models/id/has-uuid';
import { DialogService } from '@core/services/dialog.service';
@ -82,7 +76,7 @@ export class PersistentDetailsDialogComponent extends DialogComponent<Persistent
params: [''],
retries: [''],
response: [''],
additionalInfo: [null]
additionalInfo: ['']
}
);
this.loadPersistentFields(data.persistentRequest);
@ -90,35 +84,18 @@ export class PersistentDetailsDialogComponent extends DialogComponent<Persistent
}
loadPersistentFields(request: PersistentRpc) {
this.persistentFormGroup.get('rpcId')
.patchValue(this.translate.instant('widgets.persistent-table.details-title') + request.id.id);
this.persistentFormGroup.get('createdTime')
.patchValue(this.datePipe.transform(request.createdTime, 'yyyy-MM-dd HH:mm:ss'));
this.persistentFormGroup.get('expirationTime')
.patchValue(this.datePipe.transform(request.expirationTime, 'yyyy-MM-dd HH:mm:ss'));
this.persistentFormGroup.get('messageType')
.patchValue(this.translate.instant('widgets.persistent-table.message-types.' + request.request.oneway)
);
this.persistentFormGroup.get('status')
.patchValue(this.translate.instant(rpcStatusTranslation.get(request.status)));
this.persistentFormGroup.get('method')
.patchValue(request.request.body.method);
if (isDefinedAndNotNull(request.request.retries)) {
this.persistentFormGroup.get('retries')
.patchValue(request.request.retries);
}
if (isDefinedAndNotNull(request.response)) {
this.persistentFormGroup.get('response')
.patchValue(request.response);
}
if (isDefinedAndNotNull(request.request.body.params)) {
this.persistentFormGroup.get('params')
.patchValue(JSON.parse(request.request.body.params));
}
if (isDefinedAndNotNull(request.additionalInfo)) {
this.persistentFormGroup.get('additionalInfo')
.patchValue(request.additionalInfo);
}
this.persistentFormGroup.patchValue({
rpcId: this.translate.instant('widgets.persistent-table.details-title') + request.id.id,
createdTime: this.datePipe.transform(request.createdTime, 'yyyy-MM-dd HH:mm:ss'),
expirationTime: this.datePipe.transform(request.expirationTime, 'yyyy-MM-dd HH:mm:ss'),
messageType: this.translate.instant('widgets.persistent-table.message-types.' + request.request.oneway),
status: this.translate.instant(rpcStatusTranslation.get(request.status)),
method: request.request.body.method,
retries: request.request.retries || null,
response: request.response || null,
params: JSON.parse(request.request.body.params) || null,
additionalInfo: request.additionalInfo || null
}, {emitEvent: false});
}
ngOnInit(): void {
@ -138,12 +115,10 @@ export class PersistentDetailsDialogComponent extends DialogComponent<Persistent
this.translate.instant('action.yes')
).subscribe((res) => {
if (res) {
if (res) {
this.deviceService.deletePersistedRpc(persistentRpc.id.id).subscribe(() => {
this.persistentUpdated = true;
this.close();
});
}
this.deviceService.deletePersistedRpc(persistentRpc.id.id).subscribe(() => {
this.persistentUpdated = true;
this.close();
});
}
});
}

2
ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.html

@ -19,7 +19,7 @@
<mat-form-field fxFlex class="mat-block" floatLabel="always">
<mat-label translate>widgets.persistent-table.rpc-status-list</mat-label>
<mat-select formControlName="rpcStatus"
placeholder="{{ !persistentFilterFormGroup.get('rpcStatus').value?.length ? ('widgets.persistent-table.any-status' | translate) : '' }}">
placeholder="{{ rpcSearchPlaceholder }}">
<mat-option [value]="null">
{{ 'widgets.persistent-table.rpc-search-status-all' | translate }}
</mat-option>

1
ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.scss

@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
:host {
width: 100%;
height: 100%;

16
ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-filter-panel.component.ts

@ -18,6 +18,7 @@ import { Component, Inject, InjectionToken } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import { OverlayRef } from '@angular/cdk/overlay';
import { RpcStatus, rpcStatusTranslation } from '@shared/models/rpc.models';
import { TranslateService } from '@ngx-translate/core';
export const PERSISTENT_FILTER_PANEL_DATA = new InjectionToken<any>('AlarmFilterPanelData');
@ -35,26 +36,21 @@ export class PersistentFilterPanelComponent {
public persistentFilterFormGroup: FormGroup;
public result: PersistentFilterPanelData;
public rpcSearchStatusTranslationMap = rpcStatusTranslation;
public rpcSearchPlaceholder: string;
public persistentSearchStatuses = [
RpcStatus.QUEUED,
RpcStatus.SENT,
RpcStatus.DELIVERED,
RpcStatus.SUCCESSFUL,
RpcStatus.TIMEOUT,
RpcStatus.EXPIRED,
RpcStatus.FAILED
];
public persistentSearchStatuses = Object.keys(RpcStatus);
constructor(@Inject(PERSISTENT_FILTER_PANEL_DATA)
public data: PersistentFilterPanelData,
public overlayRef: OverlayRef,
private fb: FormBuilder) {
private fb: FormBuilder,
private translate: TranslateService) {
this.persistentFilterFormGroup = this.fb.group(
{
rpcStatus: this.data.rpcStatus
}
);
this.rpcSearchPlaceholder = this.translate.instant('widgets.persistent-table.any-status');
}
update() {

2
ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.html

@ -15,7 +15,7 @@
limitations under the License.
-->
<div #persistentWidgetContainer class="tb-table-widget tb-absolute-fill">
<div class="tb-table-widget tb-absolute-fill">
<div fxFlex fxLayout="column" class="tb-absolute-fill">
<div fxFlex class="table-container">
<table mat-table [dataSource]="persistentDatasource"

1
ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.scss

@ -16,6 +16,7 @@
:host {
width: 100%;
height: 100%;
display: block;
.tb-table-widget {
.table-container {
position: relative;

129
ui-ngx/src/app/modules/home/components/widget/lib/rpc/persistent-table.component.ts

@ -15,6 +15,7 @@
///
import {
ChangeDetectorRef,
Component,
ElementRef,
Injector,
@ -30,10 +31,11 @@ import { AppState } from '@core/core.state';
import { WidgetContext } from '@home/models/widget-component.models';
import { WidgetConfig } from '@shared/models/widget.models';
import { IWidgetSubscription } from '@core/api/widget-api.models';
import { BehaviorSubject, merge, Observable, of, ReplaySubject } from 'rxjs';
import { BehaviorSubject, merge, Observable, of, ReplaySubject, Subject, throwError } from 'rxjs';
import { catchError, map, tap } from 'rxjs/operators';
import {
constructTableCssString, noDataMessage,
constructTableCssString,
noDataMessage,
TableCellButtonActionDescriptor,
TableWidgetSettings
} from '@home/components/widget/lib/table-widget.models';
@ -45,9 +47,11 @@ import { CollectionViewer, DataSource } from '@angular/cdk/collections';
import { emptyPageData, PageData } from '@shared/models/page/page-data';
import {
PersistentRpc,
PersistentRpcData, RequestData,
PersistentRpcData,
RequestData,
RpcStatus,
rpcStatusColors, rpcStatusTranslation
rpcStatusColors,
rpcStatusTranslation
} from '@shared/models/rpc.models';
import { PageLink } from '@shared/models/page/page-link';
import { Direction, SortOrder, sortOrderFromString } from '@shared/models/page/sort-order';
@ -64,11 +68,14 @@ import {
import { ConnectedPosition, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
import {
PERSISTENT_FILTER_PANEL_DATA, PersistentFilterPanelComponent, PersistentFilterPanelData
PERSISTENT_FILTER_PANEL_DATA,
PersistentFilterPanelComponent,
PersistentFilterPanelData
} from '@home/components/widget/lib/rpc/persistent-filter-panel.component';
import { PersistentAddDialogComponent } from '@home/components/widget/lib/rpc/persistent-add-dialog.component';
import { ResizeObserver } from '@juggle/resize-observer';
import { hidePageSizePixelValue } from '@shared/models/constants';
import { HttpErrorResponse } from '@angular/common/http';
interface PersistentTableWidgetSettings extends TableWidgetSettings {
defaultSortOrder: string;
@ -99,7 +106,6 @@ export class PersistentTableComponent extends PageComponent implements OnInit {
@Input()
ctx: WidgetContext;
@ViewChild('persistentWidgetContainer', {static: true}) persistentWidgetContainerRef: ElementRef;
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
@ -110,7 +116,7 @@ export class PersistentTableComponent extends PageComponent implements OnInit {
private allowSendRequest = true;
private defaultPageSize = 10;
private defaultSortOrder = '-createdTime';
private rpcStatusFilter: RpcStatus | null = null;
private rpcStatusFilter: RpcStatus;
private displayDetails = true;
private allowDelete = true;
private displayTableColumns: string[];
@ -137,7 +143,8 @@ export class PersistentTableComponent extends PageComponent implements OnInit {
private translate: TranslateService,
private dialogService: DialogService,
private deviceService: DeviceService,
private dialog: MatDialog) {
private dialog: MatDialog,
private cd: ChangeDetectorRef) {
super(store);
}
@ -150,13 +157,13 @@ export class PersistentTableComponent extends PageComponent implements OnInit {
this.ctx.updateWidgetParams();
if (this.displayPagination) {
this.widgetResize$ = new ResizeObserver(() => {
const showHidePageSize = this.persistentWidgetContainerRef.nativeElement.offsetWidth < hidePageSizePixelValue;
const showHidePageSize = this.elementRef.nativeElement.offsetWidth < hidePageSizePixelValue;
if (showHidePageSize !== this.hidePageSize) {
this.hidePageSize = showHidePageSize;
this.ctx.detectChanges();
this.cd.markForCheck();
}
});
this.widgetResize$.observe(this.persistentWidgetContainerRef.nativeElement);
this.widgetResize$.observe(this.elementRef.nativeElement);
}
}
@ -250,7 +257,7 @@ export class PersistentTableComponent extends PageComponent implements OnInit {
this.displayedColumns.push('actions');
}
this.persistentDatasource = new PersistentDatasource(this.translate, this.subscription);
this.persistentDatasource = new PersistentDatasource(this.translate, this.subscription, this.ctx);
const cssString = constructTableCssString(this.widgetConfig);
const cssParser = new cssjs();
@ -300,11 +307,9 @@ export class PersistentTableComponent extends PageComponent implements OnInit {
this.translate.instant('action.yes')
).subscribe((res) => {
if (res) {
if (res) {
this.deviceService.deletePersistedRpc(persistentRpc.id.id).subscribe(() => {
this.reloadPersistentRequests();
});
}
this.deviceService.deletePersistedRpc(persistentRpc.id.id).subscribe(() => {
this.reloadPersistentRequests();
});
}
});
}
@ -345,7 +350,7 @@ export class PersistentTableComponent extends PageComponent implements OnInit {
panelClass: ['tb-dialog', 'tb-fullscreen-dialog']
}).afterClosed().subscribe(
(requestData) => {
if (requestData.persistentUpdated) {
if (requestData) {
this.sendRequests(requestData);
}
}
@ -440,11 +445,16 @@ class PersistentDatasource implements DataSource<PersistentRpcData> {
private persistentSubject = new BehaviorSubject<PersistentRpcData[]>([]);
private pageDataSubject = new BehaviorSubject<PageData<PersistentRpcData>>(emptyPageData<PersistentRpcData>());
private rpcErrorText: string;
private executingSubjects: Array<Subject<any>>;
private executingRpcRequest = false;
public dataLoading = true;
public pageData$ = this.pageDataSubject.asObservable();
constructor(private translate: TranslateService,
private subscription: IWidgetSubscription) {
private subscription: IWidgetSubscription,
private ctx: WidgetContext) {
}
connect(collectionViewer: CollectionViewer): Observable<PersistentRpcData[] | ReadonlyArray<PersistentRpcData>> {
@ -462,11 +472,11 @@ class PersistentDatasource implements DataSource<PersistentRpcData> {
this.pageDataSubject.next(pageData);
}
loadPersistent(pageLink: PageLink, keyFilter: RpcStatus) {
loadPersistent(pageLink: PageLink, rpcStatusFilter: RpcStatus) {
this.dataLoading = true;
const result = new ReplaySubject<PageData<PersistentRpcData>>();
this.fetchEntities(pageLink, keyFilter).pipe(
this.fetchEntities(pageLink, rpcStatusFilter).pipe(
catchError(() => of(emptyPageData<PersistentRpcData>())),
).subscribe(
(pageData) => {
@ -479,8 +489,81 @@ class PersistentDatasource implements DataSource<PersistentRpcData> {
return result;
}
fetchEntities(pageLink: PageLink, keyFilter: RpcStatus): Observable<PageData<PersistentRpcData>> {
return this.subscription.subscribeForPersistentRequests(pageLink, keyFilter);
fetchEntities(pageLink: PageLink, rpcStatusFilter: RpcStatus): Observable<PageData<PersistentRpcData>> {
if (!this.subscription.rpcEnabled) {
return throwError(new Error('Rpc disabled!'));
} else if (!this.subscription.targetDeviceId) {
return throwError(new Error('Target device is not set!'));
}
const rpcSubject: Subject<any> = new Subject<any>();
this.ctx.deviceService.getPersistedRpcRequests(this.subscription.targetDeviceId, pageLink, rpcStatusFilter).subscribe(
(responseBody) => {
rpcSubject.next(responseBody);
rpcSubject.complete();
},
(rejection: HttpErrorResponse) => {
this.rpcErrorText = null;
this.executingSubjects = [];
const index = this.executingSubjects.indexOf(rpcSubject);
if (index >= 0) {
this.executingSubjects.splice(index, 1);
}
this.executingRpcRequest = this.executingSubjects.length > 0;
this.subscription.options.callbacks.rpcStateChanged(this.subscription);
if (!this.executingRpcRequest || rejection.status === 504) {
this.subscription.rpcRejection = rejection;
if (rejection.status === 504) {
this.subscription.rpcErrorText = 'Request Timeout.';
} else {
this.subscription.rpcErrorText = 'Error : ' + rejection.status + ' - ' + rejection.statusText;
const error = this.extractRejectionErrorText(rejection);
if (error) {
this.subscription.rpcErrorText += '</br>';
this.subscription.rpcErrorText += error.message || '';
}
}
this.subscription.callbacks.onRpcFailed(this.subscription);
}
rpcSubject.error(rejection);
}
);
return rpcSubject.asObservable();
}
extractRejectionErrorText(rejection: HttpErrorResponse) {
let error = null;
if (rejection.error) {
error = rejection.error;
try {
error = rejection.error ? JSON.parse(rejection.error) : null;
} catch (e) {}
}
if (error && !error.message) {
error = this.prepareMessageFromData(error);
} else if (error && error.message) {
error = error.message;
}
return error;
}
prepareMessageFromData(data) {
if (typeof data === 'object' && data.constructor === ArrayBuffer) {
const msg = String.fromCharCode.apply(null, new Uint8Array(data));
try {
const msgObj = JSON.parse(msg);
if (msgObj.message) {
return msgObj.message;
} else {
return msg;
}
} catch (e) {
return msg;
}
} else {
return data;
}
}
isEmpty(): Observable<boolean> {

2
ui-ngx/src/app/shared/components/json-object-view.component.html

@ -18,5 +18,5 @@
<div style="background: #fff;" [ngClass]="{'fill-height': fillHeight}">
<label class="tb-title no-padding" *ngIf="label">{{ label }}</label>
<span fxFlex></span>
<div #jsonViewer id="tb-json-view" [ngClass]="{'fill-height': fillHeight}"></div>
<div #jsonViewer id="tb-json-view" [ngClass]="{'fill-height': fillHeight}"></div>
</div>

2
ui-ngx/src/app/shared/components/json-object-view.component.ts

@ -153,7 +153,7 @@ export class JsonObjectViewComponent implements OnInit {
}, 2);
}
} catch (e) {
//
console.error(e);
}
if (this.jsonViewer) {
this.jsonViewer.setValue(this.contentValue ? this.contentValue : '', -1);

1
ui-ngx/src/app/shared/models/rpc.models.ts

@ -79,7 +79,6 @@ export interface PersistentRpcData extends PersistentRpc {
}
export interface RequestData {
persistentUpdated: boolean;
method?: string;
oneWayElseTwoWay?: boolean;
persistentPollingInterval?: number;

2
ui-ngx/src/app/shared/shared.module.ts

@ -150,7 +150,7 @@ import { TogglePasswordComponent } from '@shared/components/button/toggle-passwo
import { HelpPopupComponent } from '@shared/components/help-popup.component';
import { TbPopoverComponent, TbPopoverDirective } from '@shared/components/popover.component';
import { TbStringTemplateOutletDirective } from '@shared/components/directives/sring-template-outlet.directive';
import { TbComponentOutletDirective} from '@shared/components/directives/component-outlet.directive';
import { TbComponentOutletDirective } from '@shared/components/directives/component-outlet.directive';
import { HelpMarkdownComponent } from '@shared/components/help-markdown.component';
import { MarkedOptionsService } from '@shared/components/marked-options.service';
import { TbPopoverService } from '@shared/components/popover.service';

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

@ -2395,7 +2395,7 @@
},
"rpc-search-status-all": "ВСІ",
"message-types": {
"false": "Двусторонній",
"false": "Двосторонній",
"true": "Односторонній"
}
}

Loading…
Cancel
Save