Browse Source

Merge branch 'feature/iot-hub' into feature/lts-4.3-iot-hub

pull/15540/head
Igor Kulikov 4 months ago
parent
commit
7890d2ae76
  1. 4
      ui-ngx/src/app/modules/home/components/iot-hub/device-install-dialog/device-install-dialog.component.html
  2. 7
      ui-ngx/src/app/modules/home/components/iot-hub/device-install-dialog/device-install-dialog.component.ts
  3. 22
      ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-actions.service.ts
  4. 1
      ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-card.component.scss
  5. 4
      ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-card.component.ts
  6. 10
      ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.html
  7. 27
      ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.scss

4
ui-ngx/src/app/modules/home/components/iot-hub/device-install-dialog/device-install-dialog.component.html

@ -164,8 +164,8 @@
<!-- Main dialog -->
@if (loading) {
<div class="flex items-center justify-center py-12">
<mat-spinner diameter="40"></mat-spinner>
<div class="flex h-full items-center justify-center py-12">
<mat-spinner diameter="60"></mat-spinner>
</div>
} @else {
<div class="tb-device-install-header flex items-center gap-3 py-2 pl-6 pr-2">

7
ui-ngx/src/app/modules/home/components/iot-hub/device-install-dialog/device-install-dialog.component.ts

@ -53,10 +53,10 @@ import {
InstallStepType,
stepTypeAliasMap
} from '@shared/models/iot-hub/device-package.models';
import { mergeMap } from 'rxjs/operators';
export interface DeviceInstallDialogData {
item: MpItemVersionView;
zipData: ArrayBuffer;
reviewMode?: boolean;
selectedInstallMethod?: string;
installState?: Record<string, any>;
@ -138,8 +138,11 @@ export class TbDeviceInstallDialogComponent extends DialogComponent<TbDeviceInst
async ngOnInit(): Promise<void> {
try {
const zipData = await firstValueFrom(this.iotHubApiService.getVersionFileData(this.data.item.id, { ignoreLoading: true }).pipe(
mergeMap((blob: Blob) => blob.arrayBuffer())
));
const JSZip = (await import('jszip')).default;
const zip = await JSZip.loadAsync(this.data.zipData);
const zip = await JSZip.loadAsync(zipData);
const imageExtensions = new Set(['png', 'jpg', 'jpeg', 'gif', 'svg']);
for (const [path, entry] of Object.entries(zip.files) as [string, any][]) {
if (!entry.dir) {

22
ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-actions.service.ts

@ -118,34 +118,24 @@ export class IotHubActionsService {
}
installDevice(item: MpItemVersionView): Observable<string> {
return this.fetchZipData(item).pipe(
mergeMap((zipData: ArrayBuffer) => this.openDeviceInstallDialog(item, zipData))
);
return this.openDeviceInstallDialog(item);
}
reviewDevice(item: MpItemVersionView, deviceDescriptor: DeviceInstalledItemDescriptor): Observable<any> {
return this.fetchZipData(item).pipe(
mergeMap((zipData: ArrayBuffer) => this.openDeviceInstallDialog(item, zipData, {
return this.openDeviceInstallDialog(item, {
reviewMode: true,
selectedInstallMethod: deviceDescriptor.selectedInstallMethod,
installState: deviceDescriptor.installState
}))
);
}
private fetchZipData(item: MpItemVersionView): Observable<ArrayBuffer> {
return this.iotHubApiService.getVersionFileData(item.id as string, { ignoreLoading: true }).pipe(
mergeMap((blob: Blob) => blob.arrayBuffer())
);
});
}
private openDeviceInstallDialog(item: MpItemVersionView, zipData: ArrayBuffer,
private openDeviceInstallDialog(item: MpItemVersionView,
options?: { reviewMode?: boolean; selectedInstallMethod?: string; installState?: any }): Observable<any> {
return this.dialog.open(TbDeviceInstallDialogComponent, {
return this.dialog.open<TbDeviceInstallDialogComponent, DeviceInstallDialogData>(TbDeviceInstallDialogComponent, {
panelClass: ['tb-dialog', 'tb-fullscreen-dialog-lt-md'],
disableClose: true,
autoFocus: false,
data: { item, zipData, ...options } as DeviceInstallDialogData
data: { item, ...options }
}).afterClosed();
}
}

1
ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-card.component.scss

@ -285,6 +285,7 @@
font-weight: 500;
color: rgba(0, 0, 0, 0.54);
text-transform: uppercase;
margin-right: 8px;
tb-icon {
font-size: 12px;

4
ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-card.component.ts

@ -62,8 +62,8 @@ export class TbIotHubItemCardComponent {
return null;
}
const [path, query] = this.item.image.split('?');
const original = path.endsWith('/preview') ? path.slice(0, -'/preview'.length) : path;
const resolved = query ? `${original}?${query}` : original;
const withPreview = path.endsWith('/preview') ? path : `${path}/preview`;
const resolved = query ? `${withPreview}?${query}` : withPreview;
return this.iotHubApiService.resolveResourceUrl(resolved);
}

10
ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.html

@ -69,12 +69,16 @@
</span>
}
}
<button mat-icon-button class="shrink-0" (click)="close()" type="button">
<button mat-icon-button class="dlg-close-btn-desktop" (click)="close()" type="button">
<tb-icon>close</tb-icon>
</button>
</div>
</div>
<button mat-icon-button class="dlg-close-btn-mobile" (click)="close()" type="button">
<tb-icon>close</tb-icon>
</button>
<!-- Scrollable content -->
<div class="dlg-body">
<!-- Main content -->
@ -163,7 +167,7 @@
<div class="dlg-divider"></div>
<div class="dlg-meta" [class.dlg-meta-4-col]="item.type === ItemType.SOLUTION_TEMPLATE || item.type === ItemType.DASHBOARD">
@if (showCreator) {
<div class="dlg-meta-group">
<div class="dlg-meta-group dlg-meta-creator-section">
<span class="dlg-meta-label">{{ 'iot-hub.creator' | translate }}</span>
<div class="dlg-meta-creator" role="button" tabindex="0"
[class.clickable]="mode !== 'add'"
@ -179,7 +183,7 @@
<mat-icon class="dlg-meta-creator-verified">verified</mat-icon>
}
</div>
<span class="dlg-meta-creator-name">{{ item.creatorDisplayName }}</span>
<span class="dlg-meta-creator-name" tbTruncateWithTooltip>{{ item.creatorDisplayName }}</span>
</div>
</div>
}

27
ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.scss

@ -54,6 +54,21 @@
}
.dlg-close-btn-desktop {
@media #{$mat-lt-sm} {
display: none;
}
}
.dlg-close-btn-mobile {
position: absolute;
top: 16px;
right: 12px;
@media #{$mat-gt-xs} {
display: none;
}
}
// Header icon for CF/RC — Design: 64px, rounded-8, colored bg, white icon 36px
.dlg-header-icon {
width: 64px;
@ -250,21 +265,25 @@
display: grid;
gap: 24px;
padding: 16px 24px 12px;
grid-template-columns: max-content minmax(0, max-content) minmax(auto, max-content) minmax(auto, 1fr) max-content;
grid-template-columns: minmax(0, max-content) minmax(0, max-content) minmax(auto, max-content) minmax(auto, 1fr) max-content;
&.dlg-meta-4-col {
grid-template-columns: max-content minmax(auto, max-content) minmax(auto, 1fr) max-content;
grid-template-columns: minmax(0, max-content) minmax(auto, max-content) minmax(auto, 1fr) max-content;
}
.dlg-meta-details {
display: none;
}
.dlg-meta-creator-section {
min-width: 0;
}
@media #{$mat-lt-md} {
grid-template-columns: max-content max-content max-content;
grid-template-columns: minmax(0, 1fr) max-content max-content;
&.dlg-meta-4-col {
grid-template-columns: max-content max-content max-content;
grid-template-columns: minmax(0, 1fr) max-content max-content;
}
.dlg-meta-details-section {

Loading…
Cancel
Save