UI: And confirm dialog after change ota package in device profile

This commit is contained in:
Vladyslav_Prykhodko 2021-06-02 19:03:31 +03:00
parent b978f0f7ab
commit fa3bbb2851
9 changed files with 62 additions and 18 deletions

View File

@ -18,12 +18,17 @@ import {Injectable} from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { PageLink } from '@shared/models/page/page-link';
import { defaultHttpOptionsFromConfig, RequestConfig } from './http-utils';
import {Observable} from 'rxjs';
import { forkJoin, Observable, of, throwError } from 'rxjs';
import { PageData } from '@shared/models/page/page-data';
import { DeviceProfile, DeviceProfileInfo, DeviceTransportType } from '@shared/models/device.models';
import { isDefinedAndNotNull, isEmptyStr } from '@core/utils';
import { ObjectLwM2M, ServerSecurityConfig } from '@home/components/profile/device/lwm2m/lwm2m-profile-config.models';
import { SortOrder } from '@shared/models/page/sort-order';
import { OtaPackageService } from '@core/http/ota-package.service';
import { OtaUpdateType } from '@shared/models/ota-package.models';
import { mergeMap } from 'rxjs/operators';
import { DialogService } from '@core/services/dialog.service';
import { TranslateService } from '@ngx-translate/core';
@Injectable({
providedIn: 'root'
@ -31,7 +36,10 @@ import {SortOrder} from '@shared/models/page/sort-order';
export class DeviceProfileService {
constructor(
private http: HttpClient
private http: HttpClient,
private otaPackageService: OtaPackageService,
private dialogService: DialogService,
private translate: TranslateService
) {
}
@ -70,6 +78,34 @@ export class DeviceProfileService {
);
}
public saveDeviceProfileAndConfirmOtaChange(originDeviceProfile: DeviceProfile, deviceProfile: DeviceProfile,
config?: RequestConfig): Observable<DeviceProfile> {
const tasks: Observable<number>[] = [];
if (originDeviceProfile?.id?.id && originDeviceProfile.firmwareId?.id !== deviceProfile.firmwareId?.id) {
tasks.push(this.otaPackageService.countUpdateDeviceAfterChangePackage(OtaUpdateType.FIRMWARE, deviceProfile.id.id));
} else {
tasks.push(of(0));
}
if (originDeviceProfile?.id?.id && originDeviceProfile.softwareId?.id !== deviceProfile.softwareId?.id) {
tasks.push(this.otaPackageService.countUpdateDeviceAfterChangePackage(OtaUpdateType.SOFTWARE, deviceProfile.id.id));
} else {
tasks.push(of(0));
}
return forkJoin(tasks).pipe(
mergeMap(([deviceFirmwareUpdate, deviceSoftwareUpdate]) => {
let text = '';
if (deviceFirmwareUpdate > 0) {
text += this.translate.instant('ota-update.change-firmware', {count: deviceFirmwareUpdate});
}
if (deviceSoftwareUpdate > 0) {
text += text.length ? '<br/>' : '';
text += this.translate.instant('ota-update.change-software', {count: deviceSoftwareUpdate});
}
return text !== '' ? this.dialogService.confirm('', text) : of(true);
}),
mergeMap((update) => update ? this.saveDeviceProfile(deviceProfile, config) : throwError('Canceled saving device profiles')));
}
public saveDeviceProfile(deviceProfile: DeviceProfile, config?: RequestConfig): Observable<DeviceProfile> {
return this.http.post<DeviceProfile>('/api/deviceProfile', deviceProfile, defaultHttpOptionsFromConfig(config));
}

View File

@ -120,4 +120,8 @@ export class OtaPackageService {
return this.http.delete(`/api/otaPackage/${otaPackageId}`, defaultHttpOptionsFromConfig(config));
}
public countUpdateDeviceAfterChangePackage(type: OtaUpdateType, deviceProfileId: string, config?: RequestConfig): Observable<number> {
return this.http.get<number>(`/api/devices/count/${type}?deviceProfileId=${deviceProfileId}`, defaultHttpOptionsFromConfig(config));
}
}

View File

@ -280,7 +280,7 @@ export class EntityDetailsPanelComponent extends PageComponent implements AfterV
editingEntity.additionalInfo =
mergeDeep((this.editingEntity as any).additionalInfo, this.entityComponent.entityFormValue()?.additionalInfo);
}
this.entitiesTableConfig.saveEntity(editingEntity).subscribe(
this.entitiesTableConfig.saveEntity(editingEntity, this.editingEntity).subscribe(
(entity) => {
this.entity = entity;
this.entityComponent.entity = entity;

View File

@ -66,5 +66,5 @@
<mat-error *ngIf="selectDeviceProfileFormGroup.get('deviceProfile').hasError('required')">
{{ 'device-profile.device-profile-required' | translate }}
</mat-error>
<mat-hint *ngIf="!!hint">{{ hint | translate }}</mat-hint>
<mat-hint *ngIf="hint && !disabled">{{ hint | translate }}</mat-hint>
</mat-form-field>

View File

@ -90,7 +90,7 @@ export class DeviceProfileDialogComponent extends
this.submitted = true;
if (this.deviceProfileComponent.entityForm.valid) {
this.deviceProfile = {...this.deviceProfile, ...this.deviceProfileComponent.entityFormValue()};
this.deviceProfileService.saveDeviceProfile(this.deviceProfile).subscribe(
this.deviceProfileService.saveDeviceProfileAndConfirmOtaChange(this.deviceProfile, this.deviceProfile).subscribe(
(deviceProfile) => {
this.dialogRef.close(deviceProfile);
}

View File

@ -37,7 +37,7 @@ export type EntityStringFunction<T extends BaseData<HasId>> = (entity: T) => str
export type EntityVoidFunction<T extends BaseData<HasId>> = (entity: T) => void;
export type EntityIdsVoidFunction<T extends BaseData<HasId>> = (ids: HasUUID[]) => void;
export type EntityCountStringFunction = (count: number) => string;
export type EntityTwoWayOperation<T extends BaseData<HasId>> = (entity: T) => Observable<T>;
export type EntityTwoWayOperation<T extends BaseData<HasId>> = (entity: T, originalEntity?: T) => Observable<T>;
export type EntityByIdOperation<T extends BaseData<HasId>> = (id: HasUUID) => Observable<T>;
export type EntityIdOneWayOperation = (id: HasUUID) => Observable<any>;
export type EntityActionFunction<T extends BaseData<HasId>> = (action: EntityAction<T>) => boolean;
@ -173,7 +173,7 @@ export class EntityTableConfig<T extends BaseData<HasId>, P extends PageLink = P
deleteEntitiesTitle: EntityCountStringFunction = () => '';
deleteEntitiesContent: EntityCountStringFunction = () => '';
loadEntity: EntityByIdOperation<T | L> = () => of();
saveEntity: EntityTwoWayOperation<T> = (entity) => of(entity);
saveEntity: EntityTwoWayOperation<T> = (entity, originalEntity) => of(entity);
deleteEntity: EntityIdOneWayOperation = () => of();
entitiesFetchFunction: EntitiesFetchFunction<L, P> = () => of(emptyPageData<L>());
onEntityAction: EntityActionFunction<T> = () => false;

View File

@ -104,7 +104,8 @@ export class DeviceProfilesTableConfigResolver implements Resolve<EntityTableCon
this.config.entitiesFetchFunction = pageLink => this.deviceProfileService.getDeviceProfiles(pageLink);
this.config.loadEntity = id => this.deviceProfileService.getDeviceProfile(id.id);
this.config.saveEntity = deviceProfile => this.deviceProfileService.saveDeviceProfile(deviceProfile);
this.config.saveEntity = (deviceProfile, originDeviceProfile) =>
this.deviceProfileService.saveDeviceProfileAndConfirmOtaChange(originDeviceProfile, deviceProfile);
this.config.deleteEntity = id => this.deviceProfileService.deleteDeviceProfile(id.id);
this.config.onEntityAction = action => this.onDeviceProfileAction(action);
this.config.deleteEnabled = (deviceProfile) => deviceProfile && !deviceProfile.default;

View File

@ -69,6 +69,7 @@
<tb-device-profile-autocomplete
formControlName="deviceProfileId"
required
[ngStyle]="{'padding-bottom': isAdd ? '16px': 0}"
[hint]="'ota-update.chose-compatible-device-profile'"
[editProfileEnabled]="false"
[addNewProfile]="false"

View File

@ -2155,7 +2155,9 @@
"checksum": "Checksum",
"checksum-algorithm": "Checksum algorithm",
"checksum-copied-message": "Package checksum has been copied to clipboard",
"chose-compatible-device-profile": "Choose compatible device profile",
"change-firmware": "You have changed the firmware. This may cause update of the { count, plural, 1 {1 device} other {# devices} }.",
"change-software": "You have changed the software. This may cause update of the { count, plural, 1 {1 device} other {# devices} }.",
"chose-compatible-device-profile": "Choose compatible device profile. The uploaded package will be available only for devices with the chosen profile.",
"chose-firmware-distributed-device": "Choose firmware that will be distributed to the devices",
"chose-software-distributed-device": "Choose software that will be distributed to the devices",
"content-type": "Content type",