Browse Source

feat(iot-hub): replace gateway download bar with inline markdown button

Instead of a fixed download bar above markdown, the creator writes
${gateway.downloadButton} anywhere in their markdown. It resolves to
an HTML button with data-action attribute. After markdown renders,
onMarkdownReady() attaches a click handler that calls the authenticated
DeviceService.downloadGatewayDockerComposeFile().

Usage in post-install.md:
  ${gateway.downloadButton}
pull/15508/head
Andrii Shvaika 6 months ago
parent
commit
f347c88eab
  1. 14
      ui-ngx/src/app/modules/home/components/iot-hub/device-install-dialog/device-install-dialog.component.html
  2. 34
      ui-ngx/src/app/modules/home/components/iot-hub/device-install-dialog/device-install-dialog.component.scss
  3. 25
      ui-ngx/src/app/modules/home/components/iot-hub/device-install-dialog/device-install-dialog.component.ts

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

@ -76,18 +76,10 @@
@switch (ws.type) {
@case ('instruction') {
<div class="tb-device-install-instruction">
@if (gatewayDockerComposeAvailable) {
<div class="tb-gateway-download-bar">
<span>{{ 'iot-hub.device-install-gateway-docker-compose' | translate }}</span>
<button mat-stroked-button color="primary" (click)="downloadGatewayDockerCompose()">
<mat-icon>download</mat-icon>
{{ 'action.download' | translate }}
</button>
</div>
}
<div class="tb-device-install-instruction" #instructionContainer>
<tb-markdown [data]="ws.markdown"
[usePlainMarkdown]="true">
[usePlainMarkdown]="true"
(ready)="onMarkdownReady(instructionContainer)">
</tb-markdown>
</div>
}

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

@ -123,22 +123,6 @@
min-height: 120px;
}
// Gateway download bar
.tb-gateway-download-bar {
display: flex;
align-items: center;
justify-content: space-between;
padding: 12px 16px;
margin-bottom: 16px;
background: #e3f2fd;
border-radius: 8px;
span {
font-size: 14px;
color: rgba(0, 0, 0, 0.87);
}
}
// Instruction view
.tb-device-install-instruction {
::ng-deep tb-markdown {
@ -151,6 +135,24 @@
margin-top: 0;
}
}
.tb-download-btn {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 6px 16px;
border: 1px solid #305680;
border-radius: 4px;
color: #305680;
font-size: 14px;
font-weight: 500;
text-decoration: none;
cursor: pointer;
&:hover {
background: rgba(48, 86, 128, 0.08);
}
}
}
}

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

@ -240,16 +240,17 @@ export class TbDeviceInstallDialogComponent extends DialogComponent<TbDeviceInst
}
}
get gatewayDockerComposeAvailable(): boolean {
const gateway = this.entityOutputs.get('gateway');
return !!gateway?.dockerComposeUrl;
}
downloadGatewayDockerCompose(): void {
const gateway = this.entityOutputs.get('gateway');
if (gateway?.id) {
this.deviceService.downloadGatewayDockerComposeFile(gateway.id).subscribe();
}
onMarkdownReady(container: HTMLElement): void {
const buttons = container.querySelectorAll('[data-action="download-gateway-docker-compose"]');
buttons.forEach(btn => {
btn.addEventListener('click', (e) => {
e.preventDefault();
const gateway = this.entityOutputs.get('gateway');
if (gateway?.id) {
this.deviceService.downloadGatewayDockerComposeFile(gateway.id).subscribe();
}
});
});
}
getPatternErrorMessage(field: FormFieldDefinition): string {
@ -266,6 +267,10 @@ export class TbDeviceInstallDialogComponent extends DialogComponent<TbDeviceInst
if (key in this.transportVars) {
return this.transportVars[key];
}
// Special action placeholders
if (key === 'gateway.downloadButton') {
return '<a href="#" data-action="download-gateway-docker-compose" class="tb-download-btn">⬇ Download docker-compose.yml</a>';
}
const dotIdx = key.indexOf('.');
if (dotIdx > 0) {
const alias = key.substring(0, dotIdx);

Loading…
Cancel
Save