18 changed files with 697 additions and 32 deletions
@ -0,0 +1,123 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2021 The Thingsboard Authors
|
||||
|
///
|
||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
/// you may not use this file except in compliance with the License.
|
||||
|
/// You may obtain a copy of the License at
|
||||
|
///
|
||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
///
|
||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
/// See the License for the specific language governing permissions and
|
||||
|
/// limitations under the License.
|
||||
|
///
|
||||
|
|
||||
|
import { Injectable } from '@angular/core'; |
||||
|
import { HttpClient } from '@angular/common/http'; |
||||
|
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 { catchError, map, mergeMap } from 'rxjs/operators'; |
||||
|
import { deepClone, isDefinedAndNotNull } from '@core/utils'; |
||||
|
import { InterceptorHttpParams } from '@core/interceptors/interceptor-http-params'; |
||||
|
import { InterceptorConfig } from '@core/interceptors/interceptor-config'; |
||||
|
|
||||
|
@Injectable({ |
||||
|
providedIn: 'root' |
||||
|
}) |
||||
|
export class FirmwareService { |
||||
|
constructor( |
||||
|
private http: HttpClient |
||||
|
) { |
||||
|
|
||||
|
} |
||||
|
|
||||
|
public getFirmwares(pageLink: PageLink, hasData?: boolean, config?: RequestConfig): Observable<PageData<FirmwareInfo>> { |
||||
|
let url = `/api/firmwares${pageLink.toQuery()}`; |
||||
|
if (isDefinedAndNotNull(hasData)) { |
||||
|
url += `&hasData=${hasData}`; |
||||
|
} |
||||
|
return this.http.get<PageData<FirmwareInfo>>(url, defaultHttpOptionsFromConfig(config)); |
||||
|
} |
||||
|
|
||||
|
public getFirmware(firmwareId: string, config?: RequestConfig): Observable<Firmware> { |
||||
|
return this.http.get<Firmware>(`/api/firmware/${firmwareId}`, defaultHttpOptionsFromConfig(config)); |
||||
|
} |
||||
|
|
||||
|
public getFirmwareInfo(firmwareId: string, config?: RequestConfig): Observable<FirmwareInfo> { |
||||
|
return this.http.get<FirmwareInfo>(`/api/firmware/info/${firmwareId}`, defaultHttpOptionsFromConfig(config)); |
||||
|
} |
||||
|
|
||||
|
public downloadFirmware(firmwareId: string): Observable<any> { |
||||
|
return this.http.get(`/api/firmware/${firmwareId}/download`, { responseType: 'arraybuffer', observe: 'response' }).pipe( |
||||
|
map((response) => { |
||||
|
const headers = response.headers; |
||||
|
const filename = headers.get('x-filename'); |
||||
|
const contentType = headers.get('content-type'); |
||||
|
const linkElement = document.createElement('a'); |
||||
|
try { |
||||
|
const blob = new Blob([response.body], { type: contentType }); |
||||
|
const url = URL.createObjectURL(blob); |
||||
|
linkElement.setAttribute('href', url); |
||||
|
linkElement.setAttribute('download', filename); |
||||
|
const clickEvent = new MouseEvent('click', |
||||
|
{ |
||||
|
view: window, |
||||
|
bubbles: true, |
||||
|
cancelable: false |
||||
|
} |
||||
|
); |
||||
|
linkElement.dispatchEvent(clickEvent); |
||||
|
return null; |
||||
|
} catch (e) { |
||||
|
throw e; |
||||
|
} |
||||
|
}) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
public saveFirmware(firmware: Firmware, config?: RequestConfig): Observable<Firmware> { |
||||
|
if (!firmware.file) { |
||||
|
return this.saveFirmwareInfo(firmware, config); |
||||
|
} |
||||
|
const firmwareInfo = deepClone(firmware); |
||||
|
delete firmwareInfo.file; |
||||
|
delete firmwareInfo.checksum; |
||||
|
delete firmwareInfo.checksumAlgorithm; |
||||
|
return this.saveFirmwareInfo(firmwareInfo, config).pipe( |
||||
|
mergeMap(res => { |
||||
|
return this.uploadFirmwareFile(res.id.id, firmware.file, firmware.checksumAlgorithm, firmware.checksum).pipe( |
||||
|
catchError(() => this.deleteFirmware(res.id.id)) |
||||
|
); |
||||
|
}) |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
public saveFirmwareInfo(firmware: FirmwareInfo, config?: RequestConfig): Observable<Firmware> { |
||||
|
return this.http.post<Firmware>('/api/firmware', firmware, defaultHttpOptionsFromConfig(config)); |
||||
|
} |
||||
|
|
||||
|
public uploadFirmwareFile(firmwareId: string, file: File, checksumAlgorithm?: string, |
||||
|
checksum?: string, config?: RequestConfig): Observable<any> { |
||||
|
if (!config) { |
||||
|
config = {}; |
||||
|
} |
||||
|
const formData = new FormData(); |
||||
|
formData.append('file', file); |
||||
|
let url = `/api/firmware/${firmwareId}`; |
||||
|
if (checksumAlgorithm && checksum) { |
||||
|
url += `?checksumAlgorithm=${checksumAlgorithm}&checksum=${checksum}`; |
||||
|
} |
||||
|
return this.http.post(url, formData, |
||||
|
defaultHttpUploadOptions(config.ignoreLoading, config.ignoreErrors, config.resendRequest)); |
||||
|
} |
||||
|
|
||||
|
public deleteFirmware(firmwareId: string, config?: RequestConfig) { |
||||
|
return this.http.delete(`/api/firmware/${firmwareId}`, defaultHttpOptionsFromConfig(config)); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,48 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2021 The Thingsboard Authors
|
||||
|
///
|
||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
/// you may not use this file except in compliance with the License.
|
||||
|
/// You may obtain a copy of the License at
|
||||
|
///
|
||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
///
|
||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
/// See the License for the specific language governing permissions and
|
||||
|
/// limitations under the License.
|
||||
|
///
|
||||
|
|
||||
|
import { RouterModule, Routes } from '@angular/router'; |
||||
|
import { EntitiesTableComponent } from '@home/components/entity/entities-table.component'; |
||||
|
import { Authority } from '@shared/models/authority.enum'; |
||||
|
import { NgModule } from '@angular/core'; |
||||
|
import { FirmwareTableConfigResolve } from '@home/pages/firmware/firmware-table-config.resolve'; |
||||
|
|
||||
|
const routes: Routes = [ |
||||
|
{ |
||||
|
path: 'firmwares', |
||||
|
component: EntitiesTableComponent, |
||||
|
data: { |
||||
|
auth: [Authority.TENANT_ADMIN], |
||||
|
title: 'firmware.firmware', |
||||
|
breadcrumb: { |
||||
|
label: 'firmware.firmware', |
||||
|
icon: 'memory' |
||||
|
} |
||||
|
}, |
||||
|
resolve: { |
||||
|
entitiesTableConfig: FirmwareTableConfigResolve |
||||
|
} |
||||
|
} |
||||
|
]; |
||||
|
|
||||
|
@NgModule({ |
||||
|
imports: [RouterModule.forChild(routes)], |
||||
|
exports: [RouterModule], |
||||
|
providers: [ |
||||
|
FirmwareTableConfigResolve |
||||
|
] |
||||
|
}) |
||||
|
export class FirmwareRoutingModule{ } |
||||
@ -0,0 +1,99 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2021 The Thingsboard Authors
|
||||
|
///
|
||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
/// you may not use this file except in compliance with the License.
|
||||
|
/// You may obtain a copy of the License at
|
||||
|
///
|
||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
///
|
||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
/// See the License for the specific language governing permissions and
|
||||
|
/// limitations under the License.
|
||||
|
///
|
||||
|
|
||||
|
import { Injectable } from '@angular/core'; |
||||
|
import { Resolve } from '@angular/router'; |
||||
|
import { |
||||
|
DateEntityTableColumn, |
||||
|
EntityTableColumn, |
||||
|
EntityTableConfig |
||||
|
} from '@home/models/entity/entities-table-config.models'; |
||||
|
import { Firmware, FirmwareInfo } 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'; |
||||
|
import { FirmwareService } from '@core/http/firmware.service'; |
||||
|
import { PageLink } from '@shared/models/page/page-link'; |
||||
|
import { FirmwaresComponent } from '@home/pages/firmware/firmwares.component'; |
||||
|
import { EntityAction } from '@home/models/entity/entity-component.models'; |
||||
|
import { DeviceInfo } from '@shared/models/device.models'; |
||||
|
|
||||
|
@Injectable() |
||||
|
export class FirmwareTableConfigResolve implements Resolve<EntityTableConfig<Firmware, PageLink, FirmwareInfo>> { |
||||
|
|
||||
|
private readonly config: EntityTableConfig<Firmware, PageLink, FirmwareInfo> = new EntityTableConfig<Firmware, PageLink, FirmwareInfo>(); |
||||
|
|
||||
|
constructor(private translate: TranslateService, |
||||
|
private datePipe: DatePipe, |
||||
|
private firmwareService: FirmwareService) { |
||||
|
this.config.entityType = EntityType.FIRMWARE; |
||||
|
this.config.entityComponent = FirmwaresComponent; |
||||
|
this.config.entityTranslations = entityTypeTranslations.get(EntityType.FIRMWARE); |
||||
|
this.config.entityResources = entityTypeResources.get(EntityType.FIRMWARE); |
||||
|
|
||||
|
this.config.entityTitle = (firmware) => firmware ? firmware.title : ''; |
||||
|
|
||||
|
this.config.columns.push( |
||||
|
new DateEntityTableColumn<FirmwareInfo>('createdTime', 'common.created-time', this.datePipe, '150px'), |
||||
|
new EntityTableColumn<FirmwareInfo>('title', 'firmware.title', '50%'), |
||||
|
new EntityTableColumn<FirmwareInfo>('version', 'firmware.version', '50%') |
||||
|
); |
||||
|
|
||||
|
this.config.cellActionDescriptors.push( |
||||
|
{ |
||||
|
name: this.translate.instant('firmware.export'), |
||||
|
icon: 'file_download', |
||||
|
isEnabled: (firmware) => firmware.hasData, |
||||
|
onAction: ($event, entity) => this.exportFirmware($event, entity) |
||||
|
} |
||||
|
); |
||||
|
|
||||
|
this.config.deleteEntityTitle = firmware => this.translate.instant('firmware.delete-firmware-title', |
||||
|
{ firmwareTitle: firmware.title }); |
||||
|
this.config.deleteEntityContent = () => this.translate.instant('firmware.delete-firmware-text'); |
||||
|
this.config.deleteEntitiesTitle = count => this.translate.instant('firmware.delete-firmwares-title', {count}); |
||||
|
this.config.deleteEntitiesContent = () => this.translate.instant('firmware.delete-firmwares-text'); |
||||
|
|
||||
|
this.config.entitiesFetchFunction = pageLink => this.firmwareService.getFirmwares(pageLink); |
||||
|
this.config.loadEntity = id => this.firmwareService.getFirmwareInfo(id.id); |
||||
|
this.config.saveEntity = firmware => this.firmwareService.saveFirmware(firmware); |
||||
|
this.config.deleteEntity = id => this.firmwareService.deleteFirmware(id.id); |
||||
|
|
||||
|
this.config.onEntityAction = action => this.onFirmwareAction(action); |
||||
|
} |
||||
|
|
||||
|
resolve(): EntityTableConfig<Firmware, PageLink, FirmwareInfo> { |
||||
|
this.config.tableTitle = this.translate.instant('firmware.firmware'); |
||||
|
return this.config; |
||||
|
} |
||||
|
|
||||
|
exportFirmware($event: Event, firmware: FirmwareInfo) { |
||||
|
if ($event) { |
||||
|
$event.stopPropagation(); |
||||
|
} |
||||
|
this.firmwareService.downloadFirmware(firmware.id.id).subscribe(); |
||||
|
} |
||||
|
|
||||
|
onFirmwareAction(action: EntityAction<FirmwareInfo>): boolean { |
||||
|
switch (action.action) { |
||||
|
case 'uploadFirmware': |
||||
|
this.exportFirmware(action.event, action.entity); |
||||
|
return true; |
||||
|
} |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,35 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2021 The Thingsboard Authors
|
||||
|
///
|
||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
/// you may not use this file except in compliance with the License.
|
||||
|
/// You may obtain a copy of the License at
|
||||
|
///
|
||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
///
|
||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
/// See the License for the specific language governing permissions and
|
||||
|
/// limitations under the License.
|
||||
|
///
|
||||
|
|
||||
|
import { NgModule } from '@angular/core'; |
||||
|
import { CommonModule } from '@angular/common'; |
||||
|
import { SharedModule } from '@shared/shared.module'; |
||||
|
import { HomeComponentsModule } from '@home/components/home-components.module'; |
||||
|
import { FirmwareRoutingModule } from '@home/pages/firmware/firmware-routing.module'; |
||||
|
import { FirmwaresComponent } from '@home/pages/firmware/firmwares.component'; |
||||
|
|
||||
|
@NgModule({ |
||||
|
declarations: [ |
||||
|
FirmwaresComponent |
||||
|
], |
||||
|
imports: [ |
||||
|
CommonModule, |
||||
|
SharedModule, |
||||
|
HomeComponentsModule, |
||||
|
FirmwareRoutingModule |
||||
|
] |
||||
|
}) |
||||
|
export class FirmwareModule { } |
||||
@ -0,0 +1,87 @@ |
|||||
|
<!-- |
||||
|
|
||||
|
Copyright © 2016-2021 The Thingsboard Authors |
||||
|
|
||||
|
Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
you may not use this file except in compliance with the License. |
||||
|
You may obtain a copy of the License at |
||||
|
|
||||
|
http://www.apache.org/licenses/LICENSE-2.0 |
||||
|
|
||||
|
Unless required by applicable law or agreed to in writing, software |
||||
|
distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
See the License for the specific language governing permissions and |
||||
|
limitations under the License. |
||||
|
|
||||
|
--> |
||||
|
<div class="tb-details-buttons" fxLayout.xs="column"> |
||||
|
<button mat-raised-button color="primary" fxFlex.xs |
||||
|
[disabled]="(isLoading$ | async) || !entity?.hasData" |
||||
|
(click)="onEntityAction($event, 'uploadFirmware')" |
||||
|
[fxShow]="!isEdit"> |
||||
|
{{'firmware.export' | translate }} |
||||
|
</button> |
||||
|
<button mat-raised-button color="primary" fxFlex.xs |
||||
|
[disabled]="(isLoading$ | async)" |
||||
|
(click)="onEntityAction($event, 'delete')" |
||||
|
[fxShow]="!hideDelete() && !isEdit"> |
||||
|
{{'resource.delete' | translate }} |
||||
|
</button> |
||||
|
</div> |
||||
|
<div class="mat-padding" fxLayout="column"> |
||||
|
<form [formGroup]="entityForm"> |
||||
|
<fieldset [disabled]="(isLoading$ | async) || !isEdit"> |
||||
|
<mat-hint class="tb-hint" translate *ngIf="isAdd">firmware.warning-after-save-no-edit</mat-hint> |
||||
|
<div fxLayout="row" fxLayoutGap.gt-xs="8px" fxLayout.xs="column"> |
||||
|
<mat-form-field class="mat-block" fxFlex="45"> |
||||
|
<mat-label translate>firmware.title</mat-label> |
||||
|
<input matInput formControlName="title" type="text" required> |
||||
|
<mat-error *ngIf="entityForm.get('title').hasError('required')"> |
||||
|
{{ 'firmware.title-required' | translate }} |
||||
|
</mat-error> |
||||
|
</mat-form-field> |
||||
|
<mat-form-field class="mat-block" fxFlex> |
||||
|
<mat-label translate>firmware.version</mat-label> |
||||
|
<input matInput formControlName="version" type="text" required> |
||||
|
<mat-error *ngIf="entityForm.get('version').hasError('required')"> |
||||
|
{{ 'firmware.version-required' | translate }} |
||||
|
</mat-error> |
||||
|
</mat-form-field> |
||||
|
</div> |
||||
|
<section *ngIf="isAdd" style="padding-bottom: 8px"> |
||||
|
<div fxLayout="row" fxLayoutGap.gt-xs="8px" fxLayout.xs="column"> |
||||
|
<mat-form-field class="mat-block" fxFlex="45"> |
||||
|
<mat-label translate>firmware.checksum-algorithm</mat-label> |
||||
|
<mat-select formControlName="checksumAlgorithm"> |
||||
|
<mat-option [value]=null></mat-option> |
||||
|
<mat-option *ngFor="let checksumAlgorithm of checksumAlgorithms" [value]="checksumAlgorithm"> |
||||
|
{{ checksumAlgorithmTranslationMap.get(checksumAlgorithm) }} |
||||
|
</mat-option> |
||||
|
</mat-select> |
||||
|
</mat-form-field> |
||||
|
<mat-form-field class="mat-block" fxFlex> |
||||
|
<mat-label translate>firmware.checksum</mat-label> |
||||
|
<input matInput formControlName="checksum" type="text" |
||||
|
[required]="entityForm.get('checksumAlgorithm').value != null"> |
||||
|
<mat-error *ngIf="entityForm.get('checksumAlgorithm').hasError('required')"> |
||||
|
{{ 'firmware.checksum-required' | translate }} |
||||
|
</mat-error> |
||||
|
</mat-form-field> |
||||
|
</div> |
||||
|
<tb-file-input |
||||
|
formControlName="file" |
||||
|
workFromFileObj="true" |
||||
|
required |
||||
|
dropLabel="{{'resource.drop-file' | translate}}"> |
||||
|
</tb-file-input> |
||||
|
</section> |
||||
|
<div formGroupName="additionalInfo"> |
||||
|
<mat-form-field class="mat-block"> |
||||
|
<mat-label translate>firmware.description</mat-label> |
||||
|
<textarea matInput formControlName="description" rows="2"></textarea> |
||||
|
</mat-form-field> |
||||
|
</div> |
||||
|
</fieldset> |
||||
|
</form> |
||||
|
</div> |
||||
@ -0,0 +1,112 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2021 The Thingsboard Authors
|
||||
|
///
|
||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
/// you may not use this file except in compliance with the License.
|
||||
|
/// You may obtain a copy of the License at
|
||||
|
///
|
||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
///
|
||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
/// See the License for the specific language governing permissions and
|
||||
|
/// limitations under the License.
|
||||
|
///
|
||||
|
|
||||
|
import { Component, Inject, OnDestroy, OnInit } from '@angular/core'; |
||||
|
import { Subject } from 'rxjs'; |
||||
|
import { Store } from '@ngrx/store'; |
||||
|
import { AppState } from '@core/core.state'; |
||||
|
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 { distinctUntilChanged, map, takeUntil } from 'rxjs/operators'; |
||||
|
|
||||
|
@Component({ |
||||
|
selector: 'tb-firmware', |
||||
|
templateUrl: './firmwares.component.html' |
||||
|
}) |
||||
|
export class FirmwaresComponent extends EntityComponent<Firmware> implements OnInit, OnDestroy { |
||||
|
|
||||
|
private destroy$ = new Subject(); |
||||
|
|
||||
|
checksumAlgorithms = Object.values(ChecksumAlgorithm); |
||||
|
checksumAlgorithmTranslationMap = ChecksumAlgorithmTranslationMap; |
||||
|
|
||||
|
constructor(protected store: Store<AppState>, |
||||
|
protected translate: TranslateService, |
||||
|
@Inject('entity') protected entityValue: Firmware, |
||||
|
@Inject('entitiesTableConfig') protected entitiesTableConfigValue: EntityTableConfig<Firmware>, |
||||
|
public fb: FormBuilder) { |
||||
|
super(store, fb, entityValue, entitiesTableConfigValue); |
||||
|
} |
||||
|
|
||||
|
ngOnInit() { |
||||
|
super.ngOnInit(); |
||||
|
if (this.isAdd) { |
||||
|
this.entityForm.get('checksumAlgorithm').valueChanges.pipe( |
||||
|
map(algorithm => !!algorithm), |
||||
|
distinctUntilChanged(), |
||||
|
takeUntil(this.destroy$) |
||||
|
).subscribe( |
||||
|
setAlgorithm => { |
||||
|
if (setAlgorithm) { |
||||
|
this.entityForm.get('checksum').setValidators([Validators.maxLength(1020), Validators.required]); |
||||
|
} else { |
||||
|
this.entityForm.get('checksum').clearValidators(); |
||||
|
} |
||||
|
this.entityForm.get('checksum').updateValueAndValidity({emitEvent: false}); |
||||
|
} |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
ngOnDestroy() { |
||||
|
super.ngOnDestroy(); |
||||
|
this.destroy$.next(); |
||||
|
this.destroy$.complete(); |
||||
|
} |
||||
|
|
||||
|
hideDelete() { |
||||
|
if (this.entitiesTableConfig) { |
||||
|
return !this.entitiesTableConfig.deleteEnabled(this.entity); |
||||
|
} else { |
||||
|
return false; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
buildForm(entity: Firmware): FormGroup { |
||||
|
const form = this.fb.group({ |
||||
|
title: [entity ? entity.title : '', [Validators.required, Validators.maxLength(255)]], |
||||
|
version: [entity ? entity.version : '', [Validators.required, Validators.maxLength(255)]], |
||||
|
additionalInfo: this.fb.group( |
||||
|
{ |
||||
|
description: [entity && entity.additionalInfo ? entity.additionalInfo.description : ''], |
||||
|
} |
||||
|
) |
||||
|
}); |
||||
|
if (this.isAdd) { |
||||
|
form.addControl('checksumAlgorithm', this.fb.control(null)); |
||||
|
form.addControl('checksum', this.fb.control('', Validators.maxLength(1020))); |
||||
|
form.addControl('file', this.fb.control(null, Validators.required)); |
||||
|
} |
||||
|
return form; |
||||
|
} |
||||
|
|
||||
|
updateForm(entity: Firmware) { |
||||
|
if (this.isEdit) { |
||||
|
this.entityForm.get('title').disable({emitEvent: false}); |
||||
|
this.entityForm.get('version').disable({emitEvent: false}); |
||||
|
} |
||||
|
this.entityForm.patchValue({ |
||||
|
title: entity.title, |
||||
|
version: entity.version, |
||||
|
additionalInfo: { |
||||
|
description: entity.additionalInfo ? entity.additionalInfo.description : '' |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,50 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2021 The Thingsboard Authors
|
||||
|
///
|
||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
/// you may not use this file except in compliance with the License.
|
||||
|
/// You may obtain a copy of the License at
|
||||
|
///
|
||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
///
|
||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
/// See the License for the specific language governing permissions and
|
||||
|
/// limitations under the License.
|
||||
|
///
|
||||
|
|
||||
|
import { BaseData } from '@shared/models/base-data'; |
||||
|
import { TenantId } from '@shared/models/id/tenant-id'; |
||||
|
import { FirmwareId } from '@shared/models/id/firmware-id'; |
||||
|
|
||||
|
export enum ChecksumAlgorithm { |
||||
|
MD5 = 'md5', |
||||
|
SHA256 = 'sha256', |
||||
|
CRC32 = 'crc32' |
||||
|
} |
||||
|
|
||||
|
export const ChecksumAlgorithmTranslationMap = new Map<ChecksumAlgorithm, string>( |
||||
|
[ |
||||
|
[ChecksumAlgorithm.MD5, 'MD5'], |
||||
|
[ChecksumAlgorithm.SHA256, 'SHA-256'], |
||||
|
[ChecksumAlgorithm.CRC32, 'CRC-32'] |
||||
|
] |
||||
|
); |
||||
|
|
||||
|
export interface FirmwareInfo extends BaseData<FirmwareId> { |
||||
|
tenantId?: TenantId; |
||||
|
title?: string; |
||||
|
version?: string; |
||||
|
hasData?: boolean; |
||||
|
additionalInfo?: any; |
||||
|
} |
||||
|
|
||||
|
export interface Firmware extends FirmwareInfo { |
||||
|
file?: File; |
||||
|
data: string; |
||||
|
fileName: string; |
||||
|
checksum?: ChecksumAlgorithm; |
||||
|
checksumAlgorithm?: string; |
||||
|
contentType: string; |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
///
|
||||
|
/// Copyright © 2016-2021 The Thingsboard Authors
|
||||
|
///
|
||||
|
/// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
/// you may not use this file except in compliance with the License.
|
||||
|
/// You may obtain a copy of the License at
|
||||
|
///
|
||||
|
/// http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
///
|
||||
|
/// Unless required by applicable law or agreed to in writing, software
|
||||
|
/// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
|
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
|
/// See the License for the specific language governing permissions and
|
||||
|
/// limitations under the License.
|
||||
|
///
|
||||
|
|
||||
|
import { EntityId } from '@shared/models/id/entity-id'; |
||||
|
import { EntityType } from '@shared/models/entity-type.models'; |
||||
|
|
||||
|
export class FirmwareId implements EntityId { |
||||
|
entityType = EntityType.FIRMWARE; |
||||
|
id: string; |
||||
|
constructor(id: string) { |
||||
|
this.id = id; |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue