Merge pull request #9861 from vvlladd28/bug/gateway-dashboard/download-file

Fixed download gateway launch file and refactoring downloads file
This commit is contained in:
Andrew Shvayka 2023-12-18 18:02:18 +02:00 committed by GitHub
commit 41f81b161c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 62 additions and 111 deletions

View File

@ -28,13 +28,13 @@ import {
DeviceInfo,
DeviceInfoQuery,
DeviceSearchQuery,
PublishLaunchCommand,
PublishTelemetryCommand
} from '@shared/models/device.models';
import { EntitySubtype } from '@shared/models/entity-type.models';
import { AuthService } from '@core/auth/auth.service';
import { BulkImportRequest, BulkImportResult } from '@shared/import-export/import-export.models';
import { PersistentRpc, RpcStatus } from '@shared/models/rpc.models';
import { ResourcesService } from '@core/services/resources.service';
@Injectable({
providedIn: 'root'
@ -42,7 +42,8 @@ import { PersistentRpc, RpcStatus } from '@shared/models/rpc.models';
export class DeviceService {
constructor(
private http: HttpClient
private http: HttpClient,
private resourcesService: ResourcesService
) { }
public getDeviceInfosByQuery(deviceInfoQuery: DeviceInfoQuery, config?: RequestConfig): Observable<PageData<DeviceInfo>> {
@ -215,8 +216,7 @@ export class DeviceService {
return this.http.get<PublishTelemetryCommand>(`/api/device-connectivity/${deviceId}`, defaultHttpOptionsFromConfig(config));
}
public getDevicePublishLaunchCommands(deviceId: string, config?: RequestConfig): Observable<PublishLaunchCommand> {
return this.http.get<PublishLaunchCommand>(`/api/device-connectivity/gateway-launch/${deviceId}`, defaultHttpOptionsFromConfig(config));
public downloadGatewayDockerComposeFile(deviceId: string): Observable<any> {
return this.resourcesService.downloadResource(`/api/device-connectivity/gateway-launch/${deviceId}/docker-compose/download`);
}
}

View File

@ -30,6 +30,7 @@ import {
import { catchError, map, switchMap } from 'rxjs/operators';
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';
import { blobToBase64 } from '@core/utils';
import { ResourcesService } from '@core/services/resources.service';
@Injectable({
providedIn: 'root'
@ -37,7 +38,8 @@ import { blobToBase64 } from '@core/utils';
export class ImageService {
constructor(
private http: HttpClient,
private sanitizer: DomSanitizer
private sanitizer: DomSanitizer,
private resourcesService: ResourcesService
) {
}
@ -113,34 +115,7 @@ export class ImageService {
}
public downloadImage(type: ImageResourceType, key: string): Observable<any> {
return this.http.get(`${IMAGES_URL_PREFIX}/${type}/${encodeURIComponent(key)}`, {
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;
}
})
);
return this.resourcesService.downloadResource(`${IMAGES_URL_PREFIX}/${type}/${encodeURIComponent(key)}`);
}
public deleteImage(type: ImageResourceType, key: string, force = false, config?: RequestConfig) {

View File

@ -27,12 +27,13 @@ import {
OtaPagesIds,
OtaUpdateType
} from '@shared/models/ota-package.models';
import { catchError, map, mergeMap } from 'rxjs/operators';
import { catchError, mergeMap } from 'rxjs/operators';
import { deepClone } from '@core/utils';
import { BaseData } from '@shared/models/base-data';
import { EntityId } from '@shared/models/id/entity-id';
import { TranslateService } from '@ngx-translate/core';
import { DialogService } from '@core/services/dialog.service';
import { ResourcesService } from '@core/services/resources.service';
@Injectable({
providedIn: 'root'
@ -41,7 +42,8 @@ export class OtaPackageService {
constructor(
private http: HttpClient,
private translate: TranslateService,
private dialogService: DialogService
private dialogService: DialogService,
private resourcesService: ResourcesService
) {
}
@ -65,31 +67,7 @@ export class OtaPackageService {
}
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;
}
})
);
return this.resourcesService.downloadResource(`/api/otaPackage/${otaPackageId}/download`);
}
public saveOtaPackage(otaPackage: OtaPackage, config?: RequestConfig): Observable<OtaPackage> {

View File

@ -21,15 +21,17 @@ import { defaultHttpOptionsFromConfig, RequestConfig } from '@core/http/http-uti
import { forkJoin, Observable, of } from 'rxjs';
import { PageData } from '@shared/models/page/page-data';
import { Resource, ResourceInfo, ResourceType } from '@shared/models/resource.models';
import { catchError, map, mergeMap } from 'rxjs/operators';
import { catchError, mergeMap } from 'rxjs/operators';
import { isNotEmptyStr } from '@core/utils';
import { ResourcesService } from '@core/services/resources.service';
@Injectable({
providedIn: 'root'
})
export class ResourceService {
constructor(
private http: HttpClient
private http: HttpClient,
private resourcesService: ResourcesService
) {
}
@ -55,34 +57,7 @@ export class ResourceService {
}
public downloadResource(resourceId: string): Observable<any> {
return this.http.get(`/api/resource/${resourceId}/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;
}
})
);
return this.resourcesService.downloadResource(`/api/resource/${resourceId}/download`);
}
public saveResources(resources: Resource[], config?: RequestConfig): Observable<Resource[]> {

View File

@ -33,7 +33,7 @@ import { AuthService } from '@core/auth/auth.service';
import { select, Store } from '@ngrx/store';
import { selectIsAuthenticated } from '@core/auth/auth.selectors';
import { AppState } from '@core/core.state';
import { tap } from 'rxjs/operators';
import { map, tap } from 'rxjs/operators';
declare const System;
@ -106,6 +106,37 @@ export class ResourcesService {
return this.loadResourceByType(fileType, url);
}
public downloadResource(downloadUrl: string): Observable<any> {
return this.http.get(downloadUrl, {
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 loadFactories(resourceId: string | TbResourceId, modulesMap: IModulesMap): Observable<ModulesWithFactories> {
const url = this.getDownloadUrl(resourceId);
if (this.loadedModulesAndFactories[url]) {

View File

@ -32,10 +32,10 @@
<div class="tb-form-panel-title" translate>gateway.download-configuration-file</div>
<div class="tb-form-row no-border no-padding space-between">
<div class="tb-no-data-text tb-commands-hint" translate>gateway.download-docker-compose</div>
<a mat-stroked-button color="primary" href="{{downloadUrl}}" target="_blank">
<button mat-stroked-button color="primary" (click)="download($event)">
<mat-icon>download</mat-icon>
{{ 'action.download' | translate }}
</a>
</button>
</div>
</div>

View File

@ -14,8 +14,8 @@
/// limitations under the License.
///
import { Component, Inject, Input, OnInit } from '@angular/core';
import { WINDOW } from '@core/services/window.service';
import { Component, Input } from '@angular/core';
import { DeviceService } from '@core/http/device.service';
@Component({
selector: 'tb-gateway-command',
@ -23,20 +23,20 @@ import { WINDOW } from '@core/services/window.service';
styleUrls: ['./device-gateway-command.component.scss']
})
export class DeviceGatewayCommandComponent implements OnInit {
export class DeviceGatewayCommandComponent {
@Input()
deviceId: string;
downloadUrl: string;
constructor(@Inject(WINDOW) private window: Window) {
constructor(private deviceService: DeviceService) {
}
ngOnInit(): void {
download($event: Event) {
if ($event) {
$event.stopPropagation();
}
if (this.deviceId) {
this.downloadUrl = `${this.window.location.origin}/api/device-connectivity/gateway-launch/${this.deviceId}/docker-compose/download`;
this.deviceService.downloadGatewayDockerComposeFile(this.deviceId).subscribe(() => {});
}
}
}

View File

@ -865,14 +865,6 @@ export interface PublishTelemetryCommand {
snmp?: string;
}
export interface PublishLaunchCommand {
mqtt: {
linux: string;
windows: string;
macos: string;
};
}
export const dayOfWeekTranslations = new Array<string>(
'device-profile.schedule-day.monday',
'device-profile.schedule-day.tuesday',