Browse Source

UI: Add firmware type

pull/4524/head
Vladyslav_Prykhodko 5 years ago
committed by Andrew Shvayka
parent
commit
fd8dee0a9d
  1. 2
      ui-ngx/src/app/core/http/entity.service.ts
  2. 15
      ui-ngx/src/app/core/http/firmware.service.ts
  3. 4
      ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html
  4. 2
      ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.ts
  5. 8
      ui-ngx/src/app/modules/home/components/profile/device-profile.component.html
  6. 5
      ui-ngx/src/app/modules/home/components/profile/device-profile.component.ts
  7. 4
      ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html
  8. 2
      ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.ts
  9. 8
      ui-ngx/src/app/modules/home/pages/device/device.component.html
  10. 30
      ui-ngx/src/app/modules/home/pages/device/device.component.ts
  11. 18
      ui-ngx/src/app/modules/home/pages/firmware/firmware-table-config.resolve.ts
  12. 19
      ui-ngx/src/app/modules/home/pages/firmware/firmwares.component.html
  13. 14
      ui-ngx/src/app/modules/home/pages/firmware/firmwares.component.ts
  14. 4
      ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.html
  15. 40
      ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.ts
  16. 2
      ui-ngx/src/app/shared/models/device.models.ts
  17. 19
      ui-ngx/src/app/shared/models/firmware.models.ts
  18. 9
      ui-ngx/src/assets/locale/locale.constant-en_US.json

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

15
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<PageData<FirmwareInfo>> {
let url = `/api/firmwares`;
if (isDefinedAndNotNull(hasData)) {
url += `/${hasData}`;
}
url += `${pageLink.toQuery()}`;
public getFirmwares(pageLink: PageLink, config?: RequestConfig): Observable<PageData<FirmwareInfo>> {
return this.http.get<PageData<FirmwareInfo>>(`/api/firmwares${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config));
}
public getFirmwaresInfoByDeviceProfileId(pageLink: PageLink, deviceProfileId: string, type: FirmwareType,
hasData = true, config?: RequestConfig): Observable<PageData<FirmwareInfo>> {
const url = `/api/firmwares/${deviceProfileId}/${type}/${hasData}${pageLink.toQuery()}`;
return this.http.get<PageData<FirmwareInfo>>(url, defaultHttpOptionsFromConfig(config));
}

4
ui-ngx/src/app/modules/home/components/profile/add-device-profile-dialog.component.html

@ -60,10 +60,6 @@
{{ 'device-profile.type-required' | translate }}
</mat-error>
</mat-form-field>
<tb-firmware-autocomplete
[useFullEntityId]="true"
formControlName="firmwareId">
</tb-firmware-autocomplete>
<mat-form-field class="mat-block">
<mat-label translate>device-profile.description</mat-label>
<textarea matInput formControlName="description" rows="2"></textarea>

2
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),

8
ui-ngx/src/app/modules/home/components/profile/device-profile.component.html

@ -65,8 +65,16 @@
</tb-queue-type-list>
<tb-firmware-autocomplete
[useFullEntityId]="true"
[type]="firmwareTypes.FIRMWARE"
[deviceProfileId]="deviceProfileId?.id"
formControlName="firmwareId">
</tb-firmware-autocomplete>
<tb-firmware-autocomplete
[useFullEntityId]="true"
[type]="firmwareTypes.SOFTWARE"
[deviceProfileId]="deviceProfileId?.id"
formControlName="softwareId">
</tb-firmware-autocomplete>
<mat-form-field fxHide class="mat-block">
<mat-label translate>device-profile.type</mat-label>
<mat-select formControlName="type" required>

5
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<DeviceProfile> {
deviceProfileId: EntityId;
firmwareTypes = FirmwareType;
constructor(protected store: Store<AppState>,
protected translate: TranslateService,
@Optional() @Inject('entity') protected entityValue: DeviceProfile,
@ -110,6 +113,7 @@ export class DeviceProfileComponent extends EntityComponent<DeviceProfile> {
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<DeviceProfile> {
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});
}

4
ui-ngx/src/app/modules/home/components/wizard/device-wizard-dialog.component.html

@ -48,10 +48,6 @@
<mat-label translate>device.label</mat-label>
<input matInput formControlName="label">
</mat-form-field>
<tb-firmware-autocomplete
[useFullEntityId]="true"
formControlName="firmwareId">
</tb-firmware-autocomplete>
<mat-form-field class="mat-block" style="padding-bottom: 14px;">
<mat-label translate>device-profile.transport-type</mat-label>
<mat-select formControlName="transportType" required>

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

8
ui-ngx/src/app/modules/home/pages/device/device.component.html

@ -103,8 +103,16 @@
</mat-form-field>
<tb-firmware-autocomplete
[useFullEntityId]="true"
[type]="firmwareTypes.FIRMWARE"
[deviceProfileId]="entityForm.get('deviceProfileId').value?.id"
formControlName="firmwareId">
</tb-firmware-autocomplete>
<tb-firmware-autocomplete
[useFullEntityId]="true"
[type]="firmwareTypes.SOFTWARE"
[deviceProfileId]="entityForm.get('deviceProfileId').value?.id"
formControlName="softwareId">
</tb-firmware-autocomplete>
<tb-device-data
formControlName="deviceData"
required>

30
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<DeviceInfo> {
deviceScope: 'tenant' | 'customer' | 'customer_user' | 'edge';
firmwareTypes = FirmwareType;
constructor(protected store: Store<AppState>,
protected translate: TranslateService,
@Inject('entity') protected entityValue: DeviceInfo,
@ -80,6 +83,7 @@ export class DeviceComponent extends EntityComponent<DeviceInfo> {
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<DeviceInfo> {
}
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<DeviceInfo> {
this.entityForm.markAsDirty();
}
}
this.entityForm.patchValue({
firmwareId: null,
softwareId: null
});
}
}
}

18
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<EntityTableConfig<Fir
this.config.columns.push(
new DateEntityTableColumn<FirmwareInfo>('createdTime', 'common.created-time', this.datePipe, '150px'),
new EntityTableColumn<FirmwareInfo>('title', 'firmware.title', '33%'),
new EntityTableColumn<FirmwareInfo>('version', 'firmware.version', '33%'),
new EntityTableColumn<FirmwareInfo>('fileName', 'firmware.file-name', '33%'),
new EntityTableColumn<FirmwareInfo>('title', 'firmware.title', '25%'),
new EntityTableColumn<FirmwareInfo>('version', 'firmware.version', '25%'),
new EntityTableColumn<FirmwareInfo>('type', 'firmware.type', '25%', entity => {
return this.translate.instant(FirmwareTypeTranslationMap.get(entity.type));
}),
new EntityTableColumn<FirmwareInfo>('fileName', 'firmware.file-name', '25%'),
new EntityTableColumn<FirmwareInfo>('dataSize', 'firmware.file-size', '70px', entity => {
return this.fileSize.transform(entity.dataSize || 0);
}),
new EntityTableColumn<FirmwareInfo>('checksum', 'firmware.checksum', '540px', entity => {
return `${entity.checksumAlgorithm}: ${entity.checksum}`;
return `${ChecksumAlgorithmTranslationMap.get(entity.checksumAlgorithm)}: ${entity.checksum}`;
}, () => ({}), false)
);

19
ui-ngx/src/app/modules/home/pages/firmware/firmwares.component.html

@ -67,10 +67,27 @@
</mat-error>
</mat-form-field>
</div>
<div fxLayout="row" fxLayoutGap.gt-xs="8px" fxLayout.xs="column">
<mat-form-field fxFlex="45">
<mat-label translate>firmware.type</mat-label>
<input *ngIf="!isAdd" matInput type="text" [readonly]="isEdit" [disabled]="!isEdit"
value="{{ firmwareTypeTranslationMap.get(entityForm.get('type').value) | translate }}">
<mat-select formControlName="type" required *ngIf="isAdd">
<mat-option *ngFor="let firmwareType of firmwareTypes" [value]="firmwareType">
{{ firmwareTypeTranslationMap.get(firmwareType) | translate }}
</mat-option>
</mat-select>
</mat-form-field>
<tb-device-profile-autocomplete
formControlName="deviceProfileId" fxFlex
[editProfileEnabled]="false">
</tb-device-profile-autocomplete>
</div>
<div fxLayout="row" fxLayoutGap.gt-xs="8px" fxLayoutGap.sm="8px" fxLayout.xs="column" fxLayout.md="column">
<mat-form-field class="mat-block" fxFlex="33">
<mat-label translate>firmware.checksum-algorithm</mat-label>
<input *ngIf="!isAdd" matInput formControlName="checksumAlgorithm" type="text" [readonly]="isEdit">
<input *ngIf="!isAdd" matInput type="text" [readonly]="isEdit" [disabled]="!isEdit"
value="{{ checksumAlgorithmTranslationMap.get(entityForm.get('checksumAlgorithm').value) | translate }}">
<mat-select formControlName="checksumAlgorithm" *ngIf="isAdd">
<mat-option [value]=null></mat-option>
<mat-option *ngFor="let checksumAlgorithm of checksumAlgorithms" [value]="checksumAlgorithm">

14
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<Firmware> implements OnI
checksumAlgorithms = Object.values(ChecksumAlgorithm);
checksumAlgorithmTranslationMap = ChecksumAlgorithmTranslationMap;
firmwareTypes = Object.values(FirmwareType);
firmwareTypeTranslationMap = FirmwareTypeTranslationMap;
constructor(protected store: Store<AppState>,
protected translate: TranslateService,
@ -83,6 +91,8 @@ export class FirmwaresComponent extends EntityComponent<Firmware> 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<Firmware> 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,

4
ui-ngx/src/app/shared/components/firmware/firmware-autocomplete.component.html

@ -37,11 +37,11 @@
<mat-option *ngIf="!(filteredFirmwares | async)?.length" [value]="null" class="tb-not-found">
<div class="tb-not-found-content" (click)="$event.stopPropagation()">
<div *ngIf="!textIsNotEmpty(searchText); else searchNotEmpty">
<span translate>firmware.no-firmware-text</span>
<span>{{ notFoundFirmware | translate }}</span>
</div>
<ng-template #searchNotEmpty>
<span>
{{ translate.get('firmware.no-firmware-matching',
{{ translate.get(notMatchingFirmware,
{entity: truncate.transform(searchText, true, 6, &apos;...&apos;)}) | async }}
</span>
</ng-template>

40
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, any>(
[
[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<AppState>,
@ -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 {

2
ui-ngx/src/app/shared/models/device.models.ts

@ -467,6 +467,7 @@ export interface DeviceProfile extends BaseData<DeviceProfileId> {
defaultRuleChainId?: RuleChainId;
defaultQueueName?: string;
firmwareId?: FirmwareId;
softwareId?: FirmwareId;
profileData: DeviceProfileData;
}
@ -522,6 +523,7 @@ export interface Device extends BaseData<DeviceId> {
type: string;
label: string;
firmwareId?: FirmwareId;
softwareId?: FirmwareId;
deviceProfileId?: DeviceProfileId;
deviceData?: DeviceData;
additionalInfo?: any;

19
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<ChecksumAlgorithm, string
]
);
export enum FirmwareType {
FIRMWARE = 'FIRMWARE',
SOFTWARE = 'SOFTWARE'
}
export const FirmwareTypeTranslationMap = new Map<FirmwareType, string>(
[
[FirmwareType.FIRMWARE, 'firmware.types.firmware'],
[FirmwareType.SOFTWARE, 'firmware.types.software']
]
);
export interface FirmwareInfo extends BaseData<FirmwareId> {
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;

9
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."

Loading…
Cancel
Save