27 changed files with 521 additions and 493 deletions
@ -1,123 +0,0 @@ |
|||
///
|
|||
/// 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 { ChecksumAlgorithm, Firmware, FirmwareInfo, FirmwareType } from '@shared/models/firmware.models'; |
|||
import { catchError, map, mergeMap } from 'rxjs/operators'; |
|||
import { deepClone } from '@core/utils'; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root' |
|||
}) |
|||
export class FirmwareService { |
|||
constructor( |
|||
private http: HttpClient |
|||
) { |
|||
|
|||
} |
|||
|
|||
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)); |
|||
} |
|||
|
|||
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: ChecksumAlgorithm, |
|||
checksum?: string, config?: RequestConfig): Observable<any> { |
|||
if (!config) { |
|||
config = {}; |
|||
} |
|||
const formData = new FormData(); |
|||
formData.append('file', file); |
|||
let url = `/api/firmware/${firmwareId}?checksumAlgorithm=${checksumAlgorithm}`; |
|||
if (checksum) { |
|||
url += `&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,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 { ChecksumAlgorithm, OtaPackage, OtaPackageInfo, OtaUpdateType } from '@shared/models/ota-package.models'; |
|||
import { catchError, map, mergeMap } from 'rxjs/operators'; |
|||
import { deepClone } from '@core/utils'; |
|||
|
|||
@Injectable({ |
|||
providedIn: 'root' |
|||
}) |
|||
export class OtaPackageService { |
|||
constructor( |
|||
private http: HttpClient |
|||
) { |
|||
|
|||
} |
|||
|
|||
public getOtaPackages(pageLink: PageLink, config?: RequestConfig): Observable<PageData<OtaPackageInfo>> { |
|||
return this.http.get<PageData<OtaPackageInfo>>(`/api/otaPackages${pageLink.toQuery()}`, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
public getOtaPackagesInfoByDeviceProfileId(pageLink: PageLink, deviceProfileId: string, type: OtaUpdateType, |
|||
hasData = true, config?: RequestConfig): Observable<PageData<OtaPackageInfo>> { |
|||
const url = `/api/otaPackages/${deviceProfileId}/${type}/${hasData}${pageLink.toQuery()}`; |
|||
return this.http.get<PageData<OtaPackageInfo>>(url, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
public getOtaPackage(otaPackageId: string, config?: RequestConfig): Observable<OtaPackage> { |
|||
return this.http.get<OtaPackage>(`/api/otaPackages/${otaPackageId}`, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
public getOtaPackageInfo(otaPackageId: string, config?: RequestConfig): Observable<OtaPackageInfo> { |
|||
return this.http.get<OtaPackageInfo>(`/api/otaPackage/info/${otaPackageId}`, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
public downloadOtaPackage(otaPackageId: string): Observable<any> { |
|||
return this.http.get(`/api/otaPackage/${otaPackageId}/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 saveOtaPackage(otaPackage: OtaPackage, config?: RequestConfig): Observable<OtaPackage> { |
|||
if (!otaPackage.file) { |
|||
return this.saveOtaPackageInfo(otaPackage, config); |
|||
} |
|||
const otaPackageInfo = deepClone(otaPackage); |
|||
delete otaPackageInfo.file; |
|||
delete otaPackageInfo.checksum; |
|||
delete otaPackageInfo.checksumAlgorithm; |
|||
return this.saveOtaPackageInfo(otaPackageInfo, config).pipe( |
|||
mergeMap(res => { |
|||
return this.uploadOtaPackageFile(res.id.id, otaPackage.file, otaPackage.checksumAlgorithm, otaPackage.checksum).pipe( |
|||
catchError(() => this.deleteOtaPackage(res.id.id)) |
|||
); |
|||
}) |
|||
); |
|||
} |
|||
|
|||
public saveOtaPackageInfo(otaPackageInfo: OtaPackageInfo, config?: RequestConfig): Observable<OtaPackage> { |
|||
return this.http.post<OtaPackage>('/api/otaPackage', otaPackageInfo, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
public uploadOtaPackageFile(otaPackageId: string, file: File, checksumAlgorithm: ChecksumAlgorithm, |
|||
checksum?: string, config?: RequestConfig): Observable<any> { |
|||
if (!config) { |
|||
config = {}; |
|||
} |
|||
const formData = new FormData(); |
|||
formData.append('file', file); |
|||
let url = `/api/otaPackage/${otaPackageId}?checksumAlgorithm=${checksumAlgorithm}`; |
|||
if (checksum) { |
|||
url += `&checksum=${checksum}`; |
|||
} |
|||
return this.http.post(url, formData, |
|||
defaultHttpUploadOptions(config.ignoreLoading, config.ignoreErrors, config.resendRequest)); |
|||
} |
|||
|
|||
public deleteOtaPackage(otaPackageId: string, config?: RequestConfig) { |
|||
return this.http.delete(`/api/otaPackage/${otaPackageId}`, defaultHttpOptionsFromConfig(config)); |
|||
} |
|||
|
|||
} |
|||
@ -1,115 +0,0 @@ |
|||
///
|
|||
/// 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 { |
|||
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'; |
|||
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 { FileSizePipe } from '@shared/pipe/file-size.pipe'; |
|||
|
|||
@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, |
|||
private fileSize: FileSizePipe) { |
|||
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', '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 `${ChecksumAlgorithmTranslationMap.get(entity.checksumAlgorithm)}: ${entity.checksum}`; |
|||
}, () => ({}), false) |
|||
); |
|||
|
|||
this.config.cellActionDescriptors.push( |
|||
{ |
|||
name: this.translate.instant('firmware.download'), |
|||
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,116 @@ |
|||
///
|
|||
/// 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 { |
|||
ChecksumAlgorithmTranslationMap, |
|||
OtaPackage, |
|||
OtaPackageInfo, |
|||
OtaUpdateTypeTranslationMap |
|||
} from '@shared/models/ota-package.models'; |
|||
import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models'; |
|||
import { TranslateService } from '@ngx-translate/core'; |
|||
import { DatePipe } from '@angular/common'; |
|||
import { OtaPackageService } from '@core/http/ota-package.service'; |
|||
import { PageLink } from '@shared/models/page/page-link'; |
|||
import { OtaUpdateComponent } from '@home/pages/ota-update/ota-update.component'; |
|||
import { EntityAction } from '@home/models/entity/entity-component.models'; |
|||
import { FileSizePipe } from '@shared/pipe/file-size.pipe'; |
|||
|
|||
@Injectable() |
|||
export class OtaUpdateTableConfigResolve implements Resolve<EntityTableConfig<OtaPackage, PageLink, OtaPackageInfo>> { |
|||
|
|||
private readonly config: EntityTableConfig<OtaPackage, PageLink, OtaPackageInfo> = |
|||
new EntityTableConfig<OtaPackage, PageLink, OtaPackageInfo>(); |
|||
|
|||
constructor(private translate: TranslateService, |
|||
private datePipe: DatePipe, |
|||
private otaPackageService: OtaPackageService, |
|||
private fileSize: FileSizePipe) { |
|||
this.config.entityType = EntityType.OTA_PACKAGE; |
|||
this.config.entityComponent = OtaUpdateComponent; |
|||
this.config.entityTranslations = entityTypeTranslations.get(EntityType.OTA_PACKAGE); |
|||
this.config.entityResources = entityTypeResources.get(EntityType.OTA_PACKAGE); |
|||
|
|||
this.config.entityTitle = (otaPackage) => otaPackage ? otaPackage.title : ''; |
|||
|
|||
this.config.columns.push( |
|||
new DateEntityTableColumn<OtaPackageInfo>('createdTime', 'common.created-time', this.datePipe, '150px'), |
|||
new EntityTableColumn<OtaPackageInfo>('title', 'ota-update.title', '25%'), |
|||
new EntityTableColumn<OtaPackageInfo>('version', 'ota-update.version', '25%'), |
|||
new EntityTableColumn<OtaPackageInfo>('type', 'ota-update.package-type', '25%', entity => { |
|||
return this.translate.instant(OtaUpdateTypeTranslationMap.get(entity.type)); |
|||
}), |
|||
new EntityTableColumn<OtaPackageInfo>('fileName', 'ota-update.file-name', '25%'), |
|||
new EntityTableColumn<OtaPackageInfo>('dataSize', 'ota-update.file-size', '70px', entity => { |
|||
return this.fileSize.transform(entity.dataSize || 0); |
|||
}), |
|||
new EntityTableColumn<OtaPackageInfo>('checksum', 'ota-update.checksum', '540px', entity => { |
|||
return `${ChecksumAlgorithmTranslationMap.get(entity.checksumAlgorithm)}: ${entity.checksum}`; |
|||
}, () => ({}), false) |
|||
); |
|||
|
|||
this.config.cellActionDescriptors.push( |
|||
{ |
|||
name: this.translate.instant('ota-update.download'), |
|||
icon: 'file_download', |
|||
isEnabled: (otaPackage) => otaPackage.hasData, |
|||
onAction: ($event, entity) => this.exportPackage($event, entity) |
|||
} |
|||
); |
|||
|
|||
this.config.deleteEntityTitle = otaPackage => this.translate.instant('ota-update.delete-ota-update-title', |
|||
{ title: otaPackage.title }); |
|||
this.config.deleteEntityContent = () => this.translate.instant('ota-update.delete-ota-update-text'); |
|||
this.config.deleteEntitiesTitle = count => this.translate.instant('ota-update.delete-ota-updates-title', {count}); |
|||
this.config.deleteEntitiesContent = () => this.translate.instant('ota-update.delete-ota-updates-text'); |
|||
|
|||
this.config.entitiesFetchFunction = pageLink => this.otaPackageService.getOtaPackages(pageLink); |
|||
this.config.loadEntity = id => this.otaPackageService.getOtaPackageInfo(id.id); |
|||
this.config.saveEntity = otaPackage => this.otaPackageService.saveOtaPackage(otaPackage); |
|||
this.config.deleteEntity = id => this.otaPackageService.deleteOtaPackage(id.id); |
|||
|
|||
this.config.onEntityAction = action => this.onPackageAction(action); |
|||
} |
|||
|
|||
resolve(): EntityTableConfig<OtaPackage, PageLink, OtaPackageInfo> { |
|||
this.config.tableTitle = this.translate.instant('ota-update.packages-repository'); |
|||
return this.config; |
|||
} |
|||
|
|||
exportPackage($event: Event, otaPackageInfo: OtaPackageInfo) { |
|||
if ($event) { |
|||
$event.stopPropagation(); |
|||
} |
|||
this.otaPackageService.downloadOtaPackage(otaPackageInfo.id.id).subscribe(); |
|||
} |
|||
|
|||
onPackageAction(action: EntityAction<OtaPackageInfo>): boolean { |
|||
switch (action.action) { |
|||
case 'uploadPackage': |
|||
this.exportPackage(action.event, action.entity); |
|||
return true; |
|||
} |
|||
return false; |
|||
} |
|||
|
|||
} |
|||
Loading…
Reference in new issue