Browse Source

feat(iot-hub): introduce shared tb-iot-hub-markdown component

- Add TbIotHubMarkdownComponent (home/components/iot-hub) wrapping
  tb-markdown with applyDefaultMarkdownStyle=false, the IoT Hub item
  link compile module, and forwarded lineNumbers /
  fallbackToPlainMarkdown coerced-boolean inputs.
- Carry the readme/description typography (h1..h6, p, ul/ol, li, a,
  img, code, code-wrapper / clipboard-btn, pre[language] with Prism
  tokens and line-numbers, tables) so callers don't have to override
  the default markdown styles. Tunes ported from the design:
  list margins, 6px heading bottom padding, table widths and
  padding, clipboard offsets, etc.
- Replace tb-markdown with tb-iot-hub-markdown in the item detail
  dialog (description + readme + changelog), the install / update
  dialog error blocks, and the solution install dialog. Drop the
  inline .dlg-readme markdown overrides and the
  .dlg-description ::ng-deep block, leaving only the dlg-readme
  layout tweak and a padding:0 reset for .dlg-description.
- Solution install dialog drops the now-redundant
  itemLinkCompileModules field + IotHubItemLinkModule import and the
  .table-wrapper ::ng-deep override; the iot-hub-markdown component
  carries those styles itself.
pull/15615/head
Igor Kulikov 5 months ago
parent
commit
ba8cef18a0
  1. 16
      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/iot-hub-components.module.ts
  3. 2
      ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-install-dialog.component.html
  4. 9
      ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.html
  5. 145
      ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-item-detail-dialog.component.scss
  6. 23
      ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-markdown.component.html
  7. 378
      ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-markdown.component.scss
  8. 40
      ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-markdown.component.ts
  9. 2
      ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-update-dialog.component.html
  10. 18
      ui-ngx/src/app/modules/home/components/solution/solution-install-dialog.component.html
  11. 60
      ui-ngx/src/app/modules/home/components/solution/solution-install-dialog.component.scss
  12. 7
      ui-ngx/src/app/modules/home/components/solution/solution-install-dialog.component.ts

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

@ -64,7 +64,7 @@
@case ('form') {
<div class="tb-device-install-form flex flex-col gap-2 p-6">
@if (ws.formGroup) {
<form [formGroup]="ws.formGroup">
<form [formGroup]="ws.formGroup" class="flex flex-col gap-4">
@for (field of ws.formFields; track field.key) {
@switch (field.type) {
@case ('BOOLEAN') {
@ -80,6 +80,9 @@
<mat-option [value]="opt.value">{{ opt.label }}</mat-option>
}
</mat-select>
@if (field.helpText) {
<mat-hint>{{ field.helpText }}</mat-hint>
}
@if (ws.formGroup.controls[field.key]?.hasError('required')) {
<mat-error>{{ field.label + ' is required' }}</mat-error>
}
@ -102,6 +105,9 @@
<mat-icon>autorenew</mat-icon>
</button>
}
@if (field.helpText) {
<mat-hint>{{ field.helpText }}</mat-hint>
}
@if (ws.formGroup.controls[field.key]?.hasError('required')) {
<mat-error>{{ field.label + ' is required' }}</mat-error>
}
@ -114,6 +120,9 @@
<mat-form-field appearance="outline">
<mat-label>{{ field.label }}</mat-label>
<input matInput type="number" [formControlName]="field.key">
@if (field.helpText) {
<mat-hint>{{ field.helpText }}</mat-hint>
}
@if (ws.formGroup.controls[field.key]?.hasError('required')) {
<mat-error>{{ field.label + ' is required' }}</mat-error>
}
@ -134,6 +143,9 @@
<mat-icon>autorenew</mat-icon>
</button>
}
@if (field.helpText) {
<mat-hint>{{ field.helpText }}</mat-hint>
}
@if (ws.formGroup.controls[field.key]?.hasError('required')) {
<mat-error>{{ field.label + ' is required' }}</mat-error>
}
@ -143,7 +155,7 @@
</mat-form-field>
}
}
@if (field.helpText) {
@if (field.type === 'BOOLEAN' && field.helpText) {
<div class="tb-form-field-help">{{ field.helpText }}</div>
}
@if (field.helpImage) {

7
ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-components.module.ts

@ -30,6 +30,7 @@ import { TbIotHubSearchComponent } from './iot-hub-search.component';
import { TbIotHubInstalledItemsTableComponent } from './iot-hub-installed-items-table.component';
import { TbIotHubInstalledItemsDialogComponent } from './iot-hub-installed-items-dialog.component';
import { TbPeConnectivityMethodPromptComponent } from './pe-connectivity-method-prompt.component';
import { TbIotHubMarkdownComponent } from './iot-hub-markdown.component';
import { IotHubActionsService } from './iot-hub-actions.service';
import { IotHubItemLinkModule } from './iot-hub-item-link-card/iot-hub-item-link.module';
@ -47,7 +48,8 @@ import { IotHubItemLinkModule } from './iot-hub-item-link-card/iot-hub-item-link
TbIotHubSearchComponent,
TbIotHubInstalledItemsTableComponent,
TbIotHubInstalledItemsDialogComponent,
TbPeConnectivityMethodPromptComponent
TbPeConnectivityMethodPromptComponent,
TbIotHubMarkdownComponent
],
imports: [
CommonModule,
@ -70,7 +72,8 @@ import { IotHubItemLinkModule } from './iot-hub-item-link-card/iot-hub-item-link
TbIotHubSearchComponent,
TbIotHubInstalledItemsTableComponent,
TbIotHubInstalledItemsDialogComponent,
TbPeConnectivityMethodPromptComponent
TbPeConnectivityMethodPromptComponent,
TbIotHubMarkdownComponent
]
})
export class IotHubComponentsModule { }

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

@ -45,7 +45,7 @@
<h2 class="tb-iot-hub-install-title">{{ 'iot-hub.install-error-title' | translate }}</h2>
<p class="tb-iot-hub-install-desc">{{ 'iot-hub.install-error-message' | translate:{ name: item.name } }}</p>
@if (item?.type === ItemType.SOLUTION_TEMPLATE) {
<tb-markdown class="tb-iot-hub-error-details-markdown" [data]="errorMessage"></tb-markdown>
<tb-iot-hub-markdown class="tb-iot-hub-error-details-markdown" [data]="errorMessage"></tb-iot-hub-markdown>
} @else {
<div class="tb-iot-hub-error-details">
{{ errorMessage }}

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

@ -85,7 +85,7 @@
<div class="dlg-info-text">
@if (item.description) {
<div class="dlg-description">
<tb-markdown [data]="item.description"></tb-markdown>
<tb-iot-hub-markdown [data]="item.description"></tb-iot-hub-markdown>
</div>
}
</div>
@ -150,7 +150,7 @@
<div class="dlg-info-text">
@if (item.description) {
<div class="dlg-description">
<tb-markdown [data]="item.description"></tb-markdown>
<tb-iot-hub-markdown [data]="item.description"></tb-iot-hub-markdown>
</div>
}
</div>
@ -299,12 +299,11 @@
@if (readmeContent || shouldShowChangelog()) {
<div class="dlg-readme">
@if (readmeContent) {
<tb-markdown [data]="readmeContent"
[additionalCompileModules]="itemLinkCompileModules"></tb-markdown>
<tb-iot-hub-markdown [data]="readmeContent"></tb-iot-hub-markdown>
}
@if (shouldShowChangelog()) {
<h3>{{ 'iot-hub.changelog' | translate }}</h3>
<tb-markdown [data]="item.changelog"></tb-markdown>
<tb-iot-hub-markdown [data]="item.changelog"></tb-iot-hub-markdown>
}
</div>
}

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

@ -166,23 +166,11 @@
}
// Description — rendered via tb-markdown, same overrides as dlg-readme
// Description — strip padding from tb-iot-hub-markdown so the body
// sits flush with the surrounding info layout.
.dlg-description {
::ng-deep tb-markdown .tb-markdown-view {
::ng-deep tb-iot-hub-markdown .tb-markdown-view {
padding: 0;
> p, > div {
padding: 0;
}
p {
font-size: 14px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0.2px;
color: rgba(0, 0, 0, 0.76);
margin: 0;
}
}
}
@ -451,135 +439,12 @@
color: #198038;
}
// Readme content — Design: px-24, pt-16, pb-24, gap-20
// Readme content — wraps tb-iot-hub-markdown, which carries the
// markdown-view styles. Only the changelog heading layout lives here.
.dlg-readme {
font-size: 14px;
line-height: 24px;
letter-spacing: 0.2px;
color: rgba(0, 0, 0, 0.76);
> h3 {
padding-left: 24px;
}
// Override markdown-view styles to match Design: px-24, pt-16, pb-24, gap-20
::ng-deep tb-markdown .tb-markdown-view {
padding: 16px 24px 24px;
// Headings: Design:20px SemiBold, line-height 24, tracking 0.1
// Override markdown-view's padding: 30px 32px 10px on direct headings
h1, h2, h3, h4, h5, h6 {
font-size: 20px;
font-weight: 600;
line-height: 24px;
letter-spacing: 0.1px;
color: rgba(0, 0, 0, 0.76);
margin: 0;
padding: 0;
}
// Direct child headings: override markdown-view's > h padding
> h1, > h2, > h3, > h4, > h5, > h6 {
padding: 0;
margin-top: 20px;
}
// First heading: no top margin
> :first-child {
margin-top: 0;
}
h1 {
font-size: 24px;
line-height: 32px;
padding-right: 0;
}
// Paragraphs: Design:14px Regular, tracking 0.2, line-height 24
// Override markdown-view's font-size: 16px and padding
p {
font-size: 14px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0.2px;
color: rgba(0, 0, 0, 0.76);
margin: 0;
}
> p, > div {
padding-left: 0;
padding-right: 0;
}
p + p {
margin-top: 8px;
}
// Heading followed by content: 8px gap
h1 + p, h2 + p, h3 + p,
h1 + ul, h2 + ul, h3 + ul,
h1 + ol, h2 + ol, h3 + ol {
margin-top: 8px;
}
// Lists: Design:ms-21 per li, 14px, line-height 24, no extra margin/padding
// Override markdown-view's padding-left: 62px, margin: 16px
ul, ol {
padding-left: 21px;
padding-right: 0;
margin: 0;
font-size: 14px;
line-height: 24px;
letter-spacing: 0.2px;
color: rgba(0, 0, 0, 0.76);
// Override markdown-view's heading-after-list padding
+ h1, + h2, + h3, + h4, + h5, + h6 {
padding-top: 0;
margin-top: 20px;
}
}
// List items: override markdown-view's padding-bottom: .75em
li {
padding-bottom: 0;
margin-bottom: 0;
line-height: 24px;
}
// Code blocks: keep smaller font
code:not([class*=language-]) {
font-size: 14px;
}
.tb-doc-link-btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
margin: 4px 8px 4px 0;
border: 1px solid rgba(0, 0, 0, 0.12);
border-radius: 6px;
background: #fff;
color: rgba(0, 0, 0, 0.76);
font-size: 14px;
font-weight: 500;
line-height: 20px;
text-decoration: none;
cursor: pointer;
i.material-icons {
font-size: 18px;
line-height: 18px;
color: rgba(0, 0, 0, 0.54);
}
&:hover {
background: rgba(0, 0, 0, 0.04);
border-color: rgba(0, 0, 0, 0.24);
}
}
}
}
// Carousel (solution templates)

23
ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-markdown.component.html

@ -0,0 +1,23 @@
<!--
Copyright © 2016-2026 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.
-->
<tb-markdown [data]="data"
[applyDefaultMarkdownStyle]="false"
[additionalCompileModules]="itemLinkCompileModules"
[lineNumbers]="lineNumbers"
[fallbackToPlainMarkdown]="fallbackToPlainMarkdown">
</tb-markdown>

378
ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-markdown.component.scss

@ -0,0 +1,378 @@
/**
* Copyright © 2016-2026 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.
*/
// Shared markdown styles for IoT Hub readme/description content.
// Originally in iot-hub-item-detail-dialog.component.scss (.dlg-readme).
:host {
display: block;
font-size: 14px;
line-height: 24px;
letter-spacing: 0.2px;
color: rgba(0, 0, 0, 0.76);
::ng-deep tb-markdown .tb-markdown-view {
padding: 16px 24px 24px;
&.table-wrapper {
padding: 0;
}
&:not(.table-wrapper) {
> :first-child {
margin-top: 0;
}
}
// Headings: design 20px SemiBold, line-height 24, tracking 0.1.
h1, h2, h3, h4, h5, h6 {
font-size: 20px;
font-weight: 600;
line-height: 24px;
letter-spacing: 0.1px;
color: rgba(0, 0, 0, 0.76);
margin: 0;
padding: 0;
}
> h1, > h2, > h3, > h4, > h5, > h6 {
padding: 0 0 6px;
margin-top: 20px;
}
h1 {
font-size: 24px;
line-height: 32px;
padding-right: 0;
}
// Paragraphs: design 14px Regular, tracking 0.2, line-height 24.
p {
font-size: 14px;
font-weight: 400;
line-height: 24px;
letter-spacing: 0.2px;
color: rgba(0, 0, 0, 0.76);
margin: 0;
}
> p, > div {
padding-left: 0;
padding-right: 0;
}
p + p {
margin-top: 8px;
}
h1 + p, h2 + p, h3 + p,
h1 + ul, h2 + ul, h3 + ul,
h1 + ol, h2 + ol, h3 + ol {
margin-top: 8px;
}
// Lists: design ms-21 per li, 14px, line-height 24.
ul, ol {
padding-left: 21px;
padding-right: 0;
margin: 0;
font-size: 14px;
line-height: 24px;
letter-spacing: 0.2px;
color: rgba(0, 0, 0, 0.76);
+ h1, + h2, + h3, + h4, + h5, + h6 {
padding-top: 0;
margin-top: 20px;
}
}
ul {
margin-top: 8px;
margin-bottom: 8px;
}
li {
padding-bottom: 4px;
margin-bottom: 0;
line-height: 24px;
}
// Images — ported from markdown.component.scss.
img {
max-width: 100%;
}
// Links — ported from markdown.component.scss.
a {
font-weight: 500;
color: #2a7dec;
text-decoration: none;
border: none;
&:hover {
color: #2a7dec;
text-decoration: underline;
border: none;
}
}
// Inline code — ported from markdown.component.scss.
code:not([class*=language-]) {
color: #eb5757;
font-family: monospace;
font-size: 14px;
}
// Code-wrapper + clipboard button — ported from markdown.component.scss
// so the inline copy affordance and hover state work without
// depending on the default markdown styles.
div.code-wrapper {
position: relative;
button.clipboard-btn {
pointer-events: none;
outline: none;
position: absolute;
width: 206px;
height: 32px;
top: 0;
right: 0;
background: 0 0;
border: none;
user-select: none;
&.multiline {
right: 6px;
}
p {
padding: 6px 8px 0;
top: 1px;
transition: .2s;
color: #2a7dec;
background: rgba(255, 255, 255, .85);
backdrop-filter: blur(4px);
opacity: 0;
font-weight: 500;
right: 32px;
position: absolute;
}
div {
background-color: #fff;
position: absolute;
width: 38px;
height: 28px;
top: 3px;
right: 3px;
padding: 8px 10px 0;
img {
position: initial;
width: 18px;
height: 18px;
filter: invert(51%) sepia(6%) saturate(172%) hue-rotate(177deg) brightness(94%) contrast(92%);
}
}
}
&:hover {
cursor: pointer;
pre[class*="language-"] {
border: solid 1px #2a7dec;
}
button.clipboard-btn {
p {
opacity: 1;
}
div img {
filter: invert(49%) sepia(97%) saturate(3730%) hue-rotate(200deg) brightness(95%) contrast(95%);
}
}
}
}
th, td {
div.code-wrapper {
display: inline-block;
width: 100%;
button.clipboard-btn {
top: -6px;
padding: 0 3px;
}
}
}
// Code blocks (Prism) — ported from markdown.component.scss.
pre[class*="language-"] {
font-size: 14px;
border: 1px solid rgba(42, 125, 236, .2);
border-radius: 4px;
background: 0 0;
padding: 8px 16px;
color: #212529;
.token.atrule, .token.attr-value, .token.keyword {
color: #2a7dec;
}
.token.selector, .token.attr-name, .token.string, .token.char, .token.builtin, .token.inserted {
color: #eb5757;
}
.token.punctuation {
color: #212529;
}
&.line-numbers {
padding-left: 66px;
> code span.line-numbers-rows {
top: -11px;
bottom: -11px;
left: -66px;
width: 50px;
border: none;
padding: 8px 12px 8px 18px;
text-align: right;
background: #f9fbff;
> span:before {
color: rgba(33, 37, 41, .6);
padding-right: 0;
}
}
&.no-line-numbers {
padding-left: 16px;
> code span.line-numbers-rows {
display: none;
}
}
}
}
// Tables — ported from markdown.component.scss since
// applyDefaultMarkdownStyle is false on tb-markdown.
> table {
width: 100%;
border: 1px solid rgba(42, 125, 236, .2);
border-radius: 4px;
border-collapse: unset;
border-spacing: 0;
margin-top: 20px;
margin-bottom: 20px;
overflow: hidden;
table-layout: fixed;
&.auto {
table-layout: auto;
}
> thead {
background-color: #f9fbff;
color: rgba(33, 37, 41, .6);
> tr > th {
border-bottom: 1px solid rgba(42, 125, 236, .2);
font-size: 14px;
padding: 8px 12px;
text-align: left;
margin: 0;
@media screen and (max-width: 400px) {
font-size: 12px;
padding: 8px 4px;
code:not([class*=language-]) {
font-size: 12px;
}
}
}
}
> tbody {
> tr:not(:last-child) > td {
border-bottom: 1px solid rgba(42, 125, 236, .2);
}
> tr > td {
font-size: 14px;
padding: 8px 12px;
text-align: left;
margin: 0;
color: rgba(15, 22, 29, 0.8);
@media screen and (max-width: 400px) {
font-size: 12px;
padding: 8px 4px;
code:not([class*=language-]) {
font-size: 12px;
}
}
}
}
th, td {
font-size: 14px;
padding: 8px;
margin: 0;
text-align: left;
}
td[align=center], th[align=center] {
text-align: center;
}
td[align=right], th[align=right] {
text-align: right;
}
tr td div {
padding-left: 0;
padding-right: 0;
}
}
.tb-doc-link-btn {
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
margin: 4px 8px 4px 0;
border: 1px solid rgba(0, 0, 0, 0.12);
border-radius: 6px;
background: #fff;
color: rgba(0, 0, 0, 0.76);
font-size: 14px;
font-weight: 500;
line-height: 20px;
text-decoration: none;
cursor: pointer;
i.material-icons {
font-size: 18px;
line-height: 18px;
color: rgba(0, 0, 0, 0.54);
}
&:hover {
background: rgba(0, 0, 0, 0.04);
border-color: rgba(0, 0, 0, 0.24);
}
}
}
}

40
ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-markdown.component.ts

@ -0,0 +1,40 @@
///
/// Copyright © 2016-2026 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, Input, Type } from '@angular/core';
import { coerceBoolean } from '@shared/decorators/coercion';
import { IotHubItemLinkModule } from './iot-hub-item-link-card/iot-hub-item-link.module';
@Component({
selector: 'tb-iot-hub-markdown',
standalone: false,
templateUrl: './iot-hub-markdown.component.html',
styleUrls: ['./iot-hub-markdown.component.scss']
})
export class TbIotHubMarkdownComponent {
@Input() data: string | undefined;
@Input()
@coerceBoolean()
lineNumbers = false;
@Input()
@coerceBoolean()
fallbackToPlainMarkdown = false;
readonly itemLinkCompileModules: Type<any>[] = [IotHubItemLinkModule];
}

2
ui-ngx/src/app/modules/home/components/iot-hub/iot-hub-update-dialog.component.html

@ -33,7 +33,7 @@
<h2 class="tb-iot-hub-install-title">{{ 'iot-hub.update-error-title' | translate }}</h2>
<p class="tb-iot-hub-install-desc">{{ 'iot-hub.update-error-message' | translate:{ name: data.itemName } }}</p>
@if (data?.itemType === ItemType.SOLUTION_TEMPLATE) {
<tb-markdown class="tb-iot-hub-error-details-markdown" [data]="errorMessage"></tb-markdown>
<tb-iot-hub-markdown class="tb-iot-hub-error-details-markdown" [data]="errorMessage"></tb-iot-hub-markdown>
} @else {
<div class="tb-iot-hub-error-details">
{{ errorMessage }}

18
ui-ngx/src/app/modules/home/components/solution/solution-install-dialog.component.html

@ -16,25 +16,25 @@
-->
<div style="min-width:400px;" class="tb-dialog-content">
<mat-toolbar color="primary">
<h2>@if (instructions) {<mat-icon>info_outline</mat-icon>}{{ (instructions ? 'iot-hub.solution-instructions' : 'iot-hub.solution-install-title') | translate }}</h2>
<div class="dlg-header">
@if (instructions) {<mat-icon>info_outline</mat-icon>}
<div class="dlg-title">{{ (instructions ? 'iot-hub.solution-instructions' : 'iot-hub.solution-install-title') | translate }}</div>
<span class="flex-1"></span>
<button mat-icon-button
(click)="close()"
type="button">
<mat-icon class="material-icons">close</mat-icon>
</button>
</mat-toolbar>
</div>
<div mat-dialog-content>
<tb-markdown [data]="details"
[additionalCompileModules]="itemLinkCompileModules"
lineNumbers
fallbackToPlainMarkdown></tb-markdown>
<tb-iot-hub-markdown [data]="details"
[lineNumbers]="true"
[fallbackToPlainMarkdown]="true"></tb-iot-hub-markdown>
</div>
<div mat-dialog-actions class="flex flex-row items-center justify-end">
<button mat-button color="primary"
<button mat-button
type="button"
(click)="close()" cdkFocusInitial>
(click)="close()">
{{ 'action.close' | translate }}
</button>
@if (dashboardId) {

60
ui-ngx/src/app/modules/home/components/solution/solution-install-dialog.component.scss

@ -17,47 +17,49 @@
@import "../../../../../scss/constants";
:host {
h2 {
.mat-icon {
padding-right: 8px;
box-sizing: initial;
vertical-align: sub;
}
.dlg-header {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 12px 8px 24px;
flex-shrink: 0;
border-bottom: 1px solid rgba(0, 0, 0, 0.12);
}
.dlg-title {
font-size: 24px;
font-weight: 500;
line-height: 32px;
color: rgba(0, 0, 0, 0.87);
}
.mat-mdc-dialog-actions {
border-top: 1px solid rgba(0, 0, 0, 0.12);
}
}
.tb-dialog-content {
max-width: 100%;
width: 1200px;
display: flex;
flex-direction: column;
@media #{$mat-lt-xxl} {
width: 900px;
}
@media #{$mat-lt-lg} {
width: 768px;
}
@media #{$mat-lt-md} {
width: 100%;
}
@media #{$mat-xs} {
min-width: 100% !important;
height: 100%;
}
}
:host ::ng-deep {
.mat-mdc-dialog-content {
tb-markdown {
.tb-markdown-view {
.table-wrapper {
overflow-y: auto;
margin: 30px 32px;
border: 1px solid rgba(42, 125, 236, .2);
border-radius: 4px;
padding: 0;
width: calc(100% - 64px);
table {
width: 100%;
table-layout: auto;
white-space: nowrap;
margin: 0;
border: 0;
border-radius: 0;
}
}
}
}
}
:host .tb-dialog-content ::ng-deep tb-iot-hub-markdown .tb-markdown-view {
padding: 0;
}

7
ui-ngx/src/app/modules/home/components/solution/solution-install-dialog.component.ts

@ -14,13 +14,10 @@
/// limitations under the License.
///
import { Component, Inject, Type } from '@angular/core';
import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
import { Router } from '@angular/router';
import { SolutionTemplateInstalledItemDescriptor } from '@shared/models/iot-hub/iot-hub-installed-item.models';
import {
IotHubItemLinkModule
} from '@home/components/iot-hub/iot-hub-item-link-card/iot-hub-item-link.module';
import {
replaceItemLinkPlaceholders
} from '@home/components/iot-hub/iot-hub-markdown.utils';
@ -42,8 +39,6 @@ export class SolutionInstallDialogComponent {
dashboardId: string | null;
instructions: boolean;
readonly itemLinkCompileModules: Type<any>[] = [IotHubItemLinkModule];
constructor(
@Inject(MAT_DIALOG_DATA) public data: SolutionInstallDialogData,
private dialogRef: MatDialogRef<SolutionInstallDialogComponent>,

Loading…
Cancel
Save