diff --git a/ui-ngx/src/app/core/http/entity.service.ts b/ui-ngx/src/app/core/http/entity.service.ts index 04d2db610d..c5ef4b8db4 100644 --- a/ui-ngx/src/app/core/http/entity.service.ts +++ b/ui-ngx/src/app/core/http/entity.service.ts @@ -361,7 +361,7 @@ export class EntityService { break; case EntityType.FIRMWARE: pageLink.sortOrder.property = 'title'; - entitiesObservable = this.firmwareService.getFirmwares(pageLink, true, config); + entitiesObservable = this.firmwareService.getFirmwares(pageLink, config); break; } return entitiesObservable; diff --git a/ui-ngx/src/app/core/http/firmware.service.ts b/ui-ngx/src/app/core/http/firmware.service.ts index 7bf42fb49e..8c3249aee6 100644 --- a/ui-ngx/src/app/core/http/firmware.service.ts +++ b/ui-ngx/src/app/core/http/firmware.service.ts @@ -20,7 +20,7 @@ import { PageLink } from '@shared/models/page/page-link'; import { defaultHttpOptionsFromConfig, defaultHttpUploadOptions, RequestConfig } from '@core/http/http-utils'; import { Observable } from 'rxjs'; import { PageData } from '@shared/models/page/page-data'; -import { Firmware, FirmwareInfo } from '@shared/models/firmware.models'; +import { Firmware, FirmwareInfo, FirmwareType } from '@shared/models/firmware.models'; import { catchError, map, mergeMap } from 'rxjs/operators'; import { deepClone, isDefinedAndNotNull } from '@core/utils'; @@ -34,12 +34,13 @@ export class FirmwareService { } - public getFirmwares(pageLink: PageLink, hasData?: boolean, config?: RequestConfig): Observable> { - let url = `/api/firmwares`; - if (isDefinedAndNotNull(hasData)) { - url += `/${hasData}`; - } - url += `${pageLink.toQuery()}`; + public getFirmwares(pageLink: PageLink, config?: RequestConfig): Observable> { + return this.http.get>(`/api/firmwares${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config)); + } + + public getFirmwaresInfoByDeviceProfileId(pageLink: PageLink, deviceProfileId: string, type: FirmwareType, + hasData = true, config?: RequestConfig): Observable> { + const url = `/api/firmwares/${deviceProfileId}/${type}/${hasData}${pageLink.toQuery()}`; return this.http.get>(url, defaultHttpOptionsFromConfig(config)); } diff --git a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html index a4f9fc3482..23219f1074 100644 --- a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html @@ -60,10 +60,6 @@ {{ 'device-profile.type-required' | translate }} - - device-profile.description diff --git a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts index 83f248db92..9ad7993857 100644 --- a/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts @@ -108,7 +108,6 @@ export class AddDeviceProfileDialogComponent extends type: [DeviceProfileType.DEFAULT, [Validators.required]], defaultRuleChainId: [null, []], defaultQueueName: ['', []], - firmwareId: [null], description: ['', []] } ); @@ -187,7 +186,6 @@ export class AddDeviceProfileDialogComponent extends transportType: this.transportConfigFormGroup.get('transportType').value, provisionType: deviceProvisionConfiguration.type, provisionDeviceKey, - firmwareId: this.deviceProfileDetailsFormGroup.get('firmwareId').value, description: this.deviceProfileDetailsFormGroup.get('description').value, profileData: { configuration: createDeviceProfileConfiguration(DeviceProfileType.DEFAULT), diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html index 5f7593a03b..5c21d65adc 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.html @@ -65,8 +65,16 @@ + + device-profile.type diff --git a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts index 23f1bd511c..d8505a0a3b 100644 --- a/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts @@ -40,6 +40,7 @@ import { EntityType } from '@shared/models/entity-type.models'; import { RuleChainId } from '@shared/models/id/rule-chain-id'; import { ServiceType } from '@shared/models/queue.models'; import { EntityId } from '@shared/models/id/entity-id'; +import { FirmwareType } from '@shared/models/firmware.models'; @Component({ selector: 'tb-device-profile', @@ -69,6 +70,8 @@ export class DeviceProfileComponent extends EntityComponent { deviceProfileId: EntityId; + firmwareTypes = FirmwareType; + constructor(protected store: Store, protected translate: TranslateService, @Optional() @Inject('entity') protected entityValue: DeviceProfile, @@ -110,6 +113,7 @@ export class DeviceProfileComponent extends EntityComponent { defaultRuleChainId: [entity && entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null, []], defaultQueueName: [entity ? entity.defaultQueueName : '', []], firmwareId: [entity ? entity.firmwareId : null], + softwareId: [entity ? entity.softwareId : null], description: [entity ? entity.description : '', []], } ); @@ -186,6 +190,7 @@ export class DeviceProfileComponent extends EntityComponent { this.entityForm.patchValue({defaultRuleChainId: entity.defaultRuleChainId ? entity.defaultRuleChainId.id : null}, {emitEvent: false}); this.entityForm.patchValue({defaultQueueName: entity.defaultQueueName}, {emitEvent: false}); this.entityForm.patchValue({firmwareId: entity.firmwareId}, {emitEvent: false}); + this.entityForm.patchValue({softwareId: entity.softwareId}, {emitEvent: false}); this.entityForm.patchValue({description: entity.description}, {emitEvent: false}); } diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html index 416b006499..245cb6503b 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html @@ -48,10 +48,6 @@ device.label - - device-profile.transport-type diff --git a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts index df925e4e21..4e2b5b2ff8 100644 --- a/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts @@ -107,7 +107,6 @@ export class DeviceWizardDialogComponent extends this.deviceWizardFormGroup = this.fb.group({ name: ['', Validators.required], label: [''], - firmwareId: [null], gateway: [false], overwriteActivityTime: [false], transportType: [DeviceTransportType.DEFAULT, Validators.required], @@ -313,7 +312,6 @@ export class DeviceWizardDialogComponent extends const device = { name: this.deviceWizardFormGroup.get('name').value, label: this.deviceWizardFormGroup.get('label').value, - firmwareId: this.deviceWizardFormGroup.get('firmwareId').value, deviceProfileId: profileId, additionalInfo: { gateway: this.deviceWizardFormGroup.get('gateway').value, diff --git a/ui-ngx/src/app/modules/home/pages/device/device.component.html b/ui-ngx/src/app/modules/home/pages/device/device.component.html index be2ce1367d..f09437662a 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device.component.html +++ b/ui-ngx/src/app/modules/home/pages/device/device.component.html @@ -103,8 +103,16 @@ + + diff --git a/ui-ngx/src/app/modules/home/pages/device/device.component.ts b/ui-ngx/src/app/modules/home/pages/device/device.component.ts index 34335b5e2f..d7f21fb2fc 100644 --- a/ui-ngx/src/app/modules/home/pages/device/device.component.ts +++ b/ui-ngx/src/app/modules/home/pages/device/device.component.ts @@ -34,6 +34,7 @@ import { ActionNotificationShow } from '@core/notification/notification.actions' import { TranslateService } from '@ngx-translate/core'; import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; import { Subject } from 'rxjs'; +import { FirmwareType } from '@shared/models/firmware.models'; @Component({ selector: 'tb-device', @@ -48,6 +49,8 @@ export class DeviceComponent extends EntityComponent { deviceScope: 'tenant' | 'customer' | 'customer_user' | 'edge'; + firmwareTypes = FirmwareType; + constructor(protected store: Store, protected translate: TranslateService, @Inject('entity') protected entityValue: DeviceInfo, @@ -80,6 +83,7 @@ export class DeviceComponent extends EntityComponent { name: [entity ? entity.name : '', [Validators.required]], deviceProfileId: [entity ? entity.deviceProfileId : null, [Validators.required]], firmwareId: [entity ? entity.firmwareId : null], + softwareId: [entity ? entity.softwareId : null], label: [entity ? entity.label : ''], deviceData: [entity ? entity.deviceData : null, [Validators.required]], additionalInfo: this.fb.group( @@ -94,19 +98,19 @@ export class DeviceComponent extends EntityComponent { } updateForm(entity: DeviceInfo) { - this.entityForm.patchValue({name: entity.name}); - this.entityForm.patchValue({deviceProfileId: entity.deviceProfileId}); - this.entityForm.patchValue({firmwareId: entity.firmwareId}); - this.entityForm.patchValue({label: entity.label}); - this.entityForm.patchValue({deviceData: entity.deviceData}); this.entityForm.patchValue({ - additionalInfo: - { - gateway: entity.additionalInfo ? entity.additionalInfo.gateway : false, - overwriteActivityTime: entity.additionalInfo ? entity.additionalInfo.overwriteActivityTime : false - } + name: entity.name, + deviceProfileId: entity.deviceProfileId, + firmwareId: entity.firmwareId, + softwareId: entity.softwareId, + label: entity.label, + deviceData: entity.deviceData, + additionalInfo: { + gateway: entity.additionalInfo ? entity.additionalInfo.gateway : false, + overwriteActivityTime: entity.additionalInfo ? entity.additionalInfo.overwriteActivityTime : false, + description: entity.additionalInfo ? entity.additionalInfo.description : '' + } }); - this.entityForm.patchValue({additionalInfo: {description: entity.additionalInfo ? entity.additionalInfo.description : ''}}); } @@ -152,6 +156,10 @@ export class DeviceComponent extends EntityComponent { this.entityForm.markAsDirty(); } } + this.entityForm.patchValue({ + firmwareId: null, + softwareId: null + }); } } } diff --git a/ui-ngx/src/app/modules/home/pages/firmware/firmware-table-config.resolve.ts b/ui-ngx/src/app/modules/home/pages/firmware/firmware-table-config.resolve.ts index b809f6f403..23efe2117b 100644 --- a/ui-ngx/src/app/modules/home/pages/firmware/firmware-table-config.resolve.ts +++ b/ui-ngx/src/app/modules/home/pages/firmware/firmware-table-config.resolve.ts @@ -21,7 +21,12 @@ import { EntityTableColumn, EntityTableConfig } from '@home/models/entity/entities-table-config.models'; -import { Firmware, FirmwareInfo } from '@shared/models/firmware.models'; +import { + ChecksumAlgorithmTranslationMap, + Firmware, + FirmwareInfo, + FirmwareTypeTranslationMap +} from '@shared/models/firmware.models'; import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models'; import { TranslateService } from '@ngx-translate/core'; import { DatePipe } from '@angular/common'; @@ -49,14 +54,17 @@ export class FirmwareTableConfigResolve implements Resolve('createdTime', 'common.created-time', this.datePipe, '150px'), - new EntityTableColumn('title', 'firmware.title', '33%'), - new EntityTableColumn('version', 'firmware.version', '33%'), - new EntityTableColumn('fileName', 'firmware.file-name', '33%'), + new EntityTableColumn('title', 'firmware.title', '25%'), + new EntityTableColumn('version', 'firmware.version', '25%'), + new EntityTableColumn('type', 'firmware.type', '25%', entity => { + return this.translate.instant(FirmwareTypeTranslationMap.get(entity.type)); + }), + new EntityTableColumn('fileName', 'firmware.file-name', '25%'), new EntityTableColumn('dataSize', 'firmware.file-size', '70px', entity => { return this.fileSize.transform(entity.dataSize || 0); }), new EntityTableColumn('checksum', 'firmware.checksum', '540px', entity => { - return `${entity.checksumAlgorithm}: ${entity.checksum}`; + return `${ChecksumAlgorithmTranslationMap.get(entity.checksumAlgorithm)}: ${entity.checksum}`; }, () => ({}), false) ); diff --git a/ui-ngx/src/app/modules/home/pages/firmware/firmwares.component.html b/ui-ngx/src/app/modules/home/pages/firmware/firmwares.component.html index 2911802a75..cba515f1d8 100644 --- a/ui-ngx/src/app/modules/home/pages/firmware/firmwares.component.html +++ b/ui-ngx/src/app/modules/home/pages/firmware/firmwares.component.html @@ -67,10 +67,27 @@ +
+ + firmware.type + + + + {{ firmwareTypeTranslationMap.get(firmwareType) | translate }} + + + + + +
firmware.checksum-algorithm - + diff --git a/ui-ngx/src/app/modules/home/pages/firmware/firmwares.component.ts b/ui-ngx/src/app/modules/home/pages/firmware/firmwares.component.ts index 8ffef239b4..adfd2050c7 100644 --- a/ui-ngx/src/app/modules/home/pages/firmware/firmwares.component.ts +++ b/ui-ngx/src/app/modules/home/pages/firmware/firmwares.component.ts @@ -22,7 +22,13 @@ import { TranslateService } from '@ngx-translate/core'; import { EntityTableConfig } from '@home/models/entity/entities-table-config.models'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { EntityComponent } from '@home/components/entity/entity.component'; -import { ChecksumAlgorithm, ChecksumAlgorithmTranslationMap, Firmware } from '@shared/models/firmware.models'; +import { + ChecksumAlgorithm, + ChecksumAlgorithmTranslationMap, + Firmware, + FirmwareType, + FirmwareTypeTranslationMap +} from '@shared/models/firmware.models'; import { distinctUntilChanged, map, takeUntil } from 'rxjs/operators'; import { ActionNotificationShow } from '@core/notification/notification.actions'; @@ -36,6 +42,8 @@ export class FirmwaresComponent extends EntityComponent implements OnI checksumAlgorithms = Object.values(ChecksumAlgorithm); checksumAlgorithmTranslationMap = ChecksumAlgorithmTranslationMap; + firmwareTypes = Object.values(FirmwareType); + firmwareTypeTranslationMap = FirmwareTypeTranslationMap; constructor(protected store: Store, protected translate: TranslateService, @@ -83,6 +91,8 @@ export class FirmwaresComponent extends EntityComponent implements OnI const form = this.fb.group({ title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]], version: [entity ? entity.version : '', [Validators.required, Validators.maxLength(255)]], + type: [entity?.type ? entity.type : FirmwareType.FIRMWARE, [Validators.required]], + deviceProfileId: [entity ? entity.deviceProfileId : null], checksumAlgorithm: [entity ? entity.checksumAlgorithm : null], checksum: [entity ? entity.checksum : '', Validators.maxLength(1020)], additionalInfo: this.fb.group( @@ -105,6 +115,8 @@ export class FirmwaresComponent extends EntityComponent implements OnI this.entityForm.patchValue({ title: entity.title, version: entity.version, + type: entity.type, + deviceProfileId: entity.deviceProfileId, checksumAlgorithm: entity.checksumAlgorithm, checksum: entity.checksum, fileName: entity.fileName, diff --git a/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.html b/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.html index 4e733b3132..7bb434e7d1 100644 --- a/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.html +++ b/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.html @@ -37,11 +37,11 @@
- firmware.no-firmware-text + {{ notFoundFirmware | translate }}
- {{ translate.get('firmware.no-firmware-matching', + {{ translate.get(notMatchingFirmware, {entity: truncate.transform(searchText, true, 6, '...')}) | async }} diff --git a/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.ts b/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.ts index 79dc170c7b..ccdf16aedd 100644 --- a/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.ts +++ b/ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.ts @@ -28,7 +28,7 @@ import { BaseData } from '@shared/models/base-data'; import { EntityService } from '@core/http/entity.service'; import { TruncatePipe } from '@shared/pipe/truncate.pipe'; import { MatAutocompleteTrigger } from '@angular/material/autocomplete'; -import { FirmwareInfo } from '@shared/models/firmware.models'; +import { FirmwareInfo, FirmwareType } from '@shared/models/firmware.models'; import { FirmwareService } from '@core/http/firmware.service'; import { PageLink } from '@shared/models/page/page-link'; import { Direction } from '@shared/models/page/sort-order'; @@ -49,6 +49,12 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn modelValue: string | null; + @Input() + type = FirmwareType.FIRMWARE; + + @Input() + deviceProfileId: string; + @Input() labelText: string; @@ -81,6 +87,23 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn private dirty = false; + private firmwareTypeTranslation = new Map( + [ + [FirmwareType.FIRMWARE, { + label: 'firmware.firmware', + required: 'firmware.firmware-required', + noFound: 'firmware.no-firmware-text', + noMatching: 'firmware.no-firmware-matching' + }], + [FirmwareType.SOFTWARE, { + label: 'firmware.software', + required: 'firmware.software-required', + noFound: 'firmware.no-software-text', + noMatching: 'firmware.no-software-matching' + }] + ] + ); + private propagateChange = (v: any) => { }; constructor(private store: Store, @@ -209,7 +232,8 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn property: 'title', direction: Direction.ASC }); - return this.firmwareService.getFirmwares(pageLink, true, {ignoreLoading: true}).pipe( + return this.firmwareService.getFirmwaresInfoByDeviceProfileId(pageLink, this.deviceProfileId, this.type, + true, {ignoreLoading: true}).pipe( map((data) => data && data.data.length ? data.data : null) ); } @@ -223,11 +247,19 @@ export class FirmwareAutocompleteComponent implements ControlValueAccessor, OnIn } get placeholderText(): string { - return this.labelText || 'firmware.firmware'; + return this.labelText || this.firmwareTypeTranslation.get(this.type).label; } get requiredErrorText(): string { - return this.requiredText || 'firmware.firmware-required'; + return this.requiredText || this.firmwareTypeTranslation.get(this.type).required; + } + + get notFoundFirmware(): string { + return this.firmwareTypeTranslation.get(this.type).noFound; + } + + get notMatchingFirmware(): string { + return this.firmwareTypeTranslation.get(this.type).noMatching; } firmwareTitleText(firmware: FirmwareInfo): string { diff --git a/ui-ngx/src/app/shared/models/device.models.ts b/ui-ngx/src/app/shared/models/device.models.ts index 6067eeee38..42c1689006 100644 --- a/ui-ngx/src/app/shared/models/device.models.ts +++ b/ui-ngx/src/app/shared/models/device.models.ts @@ -467,6 +467,7 @@ export interface DeviceProfile extends BaseData { defaultRuleChainId?: RuleChainId; defaultQueueName?: string; firmwareId?: FirmwareId; + softwareId?: FirmwareId; profileData: DeviceProfileData; } @@ -522,6 +523,7 @@ export interface Device extends BaseData { type: string; label: string; firmwareId?: FirmwareId; + softwareId?: FirmwareId; deviceProfileId?: DeviceProfileId; deviceData?: DeviceData; additionalInfo?: any; diff --git a/ui-ngx/src/app/shared/models/firmware.models.ts b/ui-ngx/src/app/shared/models/firmware.models.ts index 65dd1761bf..57c95c3c9a 100644 --- a/ui-ngx/src/app/shared/models/firmware.models.ts +++ b/ui-ngx/src/app/shared/models/firmware.models.ts @@ -17,6 +17,7 @@ import { BaseData } from '@shared/models/base-data'; import { TenantId } from '@shared/models/id/tenant-id'; import { FirmwareId } from '@shared/models/id/firmware-id'; +import { DeviceProfileId } from '@shared/models/id/device-profile-id'; export enum ChecksumAlgorithm { MD5 = 'md5', @@ -32,14 +33,28 @@ export const ChecksumAlgorithmTranslationMap = new Map( + [ + [FirmwareType.FIRMWARE, 'firmware.types.firmware'], + [FirmwareType.SOFTWARE, 'firmware.types.software'] + ] +); + export interface FirmwareInfo extends BaseData { tenantId?: TenantId; + type: FirmwareType; + deviceProfileId?: DeviceProfileId; title?: string; version?: string; hasData?: boolean; fileName: string; - checksum?: ChecksumAlgorithm; - checksumAlgorithm?: string; + checksum?: string; + checksumAlgorithm?: ChecksumAlgorithm; contentType: string; dataSize?: number; additionalInfo?: any; diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index d59ee56236..5b90961b29 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1928,6 +1928,8 @@ "idCopiedMessage": "Firmware Id has been copied to clipboard", "no-firmware-matching": "No firmware matching '{{entity}}' were found.", "no-firmware-text": "No firmwares found", + "no-software-matching": "No sowtware matching '{{entity}}' were found.", + "no-software-text": "No software found", "file-name": "File name", "file-size": "File size", "file-size-bytes": "File size in bytes", @@ -1936,8 +1938,15 @@ "firmware-required": "Firmware is required.", "search": "Search firmwares", "selected-firmware": "{ count, plural, 1 {1 firmware} other {# firmwares} } selected", + "software": "Software", + "software-required": "Software is required.", "title": "Title", "title-required": "Title is required.", + "type": "Firmware type", + "types": { + "firmware": "Firmware", + "software": "Software" + }, "version": "Version", "version-required": "Version is required.", "warning-after-save-no-edit": "Once the firmware is saved, it will not be possible to change the title and version fields."