Merge pull request #7365 from kalutkaz/fixMarkdownWidget
[3.4.2] UI: Fix markdown widget
This commit is contained in:
commit
bbc74d98dd
@ -22,7 +22,6 @@ import { EntityId } from '@shared/models/id/entity-id';
|
|||||||
import { NULL_UUID } from '@shared/models/id/has-uuid';
|
import { NULL_UUID } from '@shared/models/id/has-uuid';
|
||||||
import { EntityType, baseDetailsPageByEntityType } from '@shared/models/entity-type.models';
|
import { EntityType, baseDetailsPageByEntityType } from '@shared/models/entity-type.models';
|
||||||
import { HttpErrorResponse } from '@angular/common/http';
|
import { HttpErrorResponse } from '@angular/common/http';
|
||||||
import { letterSpacing } from 'html2canvas/dist/types/css/property-descriptors/letter-spacing';
|
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { serverErrorCodesTranslations } from '@shared/models/constants';
|
import { serverErrorCodesTranslations } from '@shared/models/constants';
|
||||||
|
|
||||||
@ -479,6 +478,18 @@ export function flatFormattedData(input: FormattedData[]): FormattedData {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function flatDataWithoutOverride(data: FormattedData[]): FormattedData {
|
||||||
|
const processingKeyValue = data[0];
|
||||||
|
for (let i = 1; i < data.length; i++) {
|
||||||
|
Object.keys(data[i]).forEach((key) => {
|
||||||
|
if (!isDefinedAndNotNull(processingKeyValue[key]) || isEmptyStr(processingKeyValue[key])) {
|
||||||
|
processingKeyValue[key] = data[i][key];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return processingKeyValue;
|
||||||
|
}
|
||||||
|
|
||||||
export function mergeFormattedData(first: FormattedData[], second: FormattedData[]): FormattedData[] {
|
export function mergeFormattedData(first: FormattedData[], second: FormattedData[]): FormattedData[] {
|
||||||
const merged = first.concat(second);
|
const merged = first.concat(second);
|
||||||
return _(merged).groupBy(el => el.$datasource)
|
return _(merged).groupBy(el => el.$datasource)
|
||||||
|
|||||||
@ -23,12 +23,11 @@ import { DatasourceData, FormattedData } from '@shared/models/widget.models';
|
|||||||
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
|
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
|
||||||
import {
|
import {
|
||||||
createLabelFromPattern,
|
createLabelFromPattern,
|
||||||
fillDataPattern,
|
flatDataWithoutOverride,
|
||||||
flatFormattedData,
|
|
||||||
formattedDataFormDatasourceData,
|
formattedDataFormDatasourceData,
|
||||||
hashCode, isDefinedAndNotNull,
|
hashCode, isDefinedAndNotNull,
|
||||||
isNotEmptyStr,
|
isNotEmptyStr,
|
||||||
parseFunction, processDataPattern,
|
parseFunction,
|
||||||
safeExecute
|
safeExecute
|
||||||
} from '@core/utils';
|
} from '@core/utils';
|
||||||
import cssjs from '@core/css/css';
|
import cssjs from '@core/css/css';
|
||||||
@ -119,7 +118,7 @@ export class MarkdownWidgetComponent extends PageComponent implements OnInit {
|
|||||||
const data = formattedDataFormDatasourceData(initialData);
|
const data = formattedDataFormDatasourceData(initialData);
|
||||||
let markdownText = this.settings.useMarkdownTextFunction ?
|
let markdownText = this.settings.useMarkdownTextFunction ?
|
||||||
safeExecute(this.markdownTextFunction, [data]) : this.settings.markdownTextPattern;
|
safeExecute(this.markdownTextFunction, [data]) : this.settings.markdownTextPattern;
|
||||||
const allData = flatFormattedData(data);
|
const allData: FormattedData = flatDataWithoutOverride(data);
|
||||||
markdownText = createLabelFromPattern(markdownText, allData);
|
markdownText = createLabelFromPattern(markdownText, allData);
|
||||||
if (this.markdownText !== markdownText) {
|
if (this.markdownText !== markdownText) {
|
||||||
this.markdownText = this.utils.customTranslation(markdownText, markdownText);
|
this.markdownText = this.utils.customTranslation(markdownText, markdownText);
|
||||||
|
|||||||
@ -23,7 +23,7 @@ import { DatasourceData, FormattedData } from '@shared/models/widget.models';
|
|||||||
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
|
import { DataKeyType } from '@shared/models/telemetry/telemetry.models';
|
||||||
import {
|
import {
|
||||||
createLabelFromPattern,
|
createLabelFromPattern,
|
||||||
flatFormattedData,
|
flatDataWithoutOverride,
|
||||||
formattedDataFormDatasourceData,
|
formattedDataFormDatasourceData,
|
||||||
isNumber,
|
isNumber,
|
||||||
isObject,
|
isObject,
|
||||||
@ -101,7 +101,7 @@ export class QrCodeWidgetComponent extends PageComponent implements OnInit, Afte
|
|||||||
const data = formattedDataFormDatasourceData(initialData);
|
const data = formattedDataFormDatasourceData(initialData);
|
||||||
const pattern = this.settings.useQrCodeTextFunction ?
|
const pattern = this.settings.useQrCodeTextFunction ?
|
||||||
safeExecute(this.qrCodeTextFunction, [data]) : this.settings.qrCodeTextPattern;
|
safeExecute(this.qrCodeTextFunction, [data]) : this.settings.qrCodeTextPattern;
|
||||||
const allData = flatFormattedData(data);
|
const allData: FormattedData = flatDataWithoutOverride(data);
|
||||||
qrCodeText = createLabelFromPattern(pattern, allData);
|
qrCodeText = createLabelFromPattern(pattern, allData);
|
||||||
this.updateQrCodeText(qrCodeText);
|
this.updateQrCodeText(qrCodeText);
|
||||||
}
|
}
|
||||||
@ -132,5 +132,4 @@ export class QrCodeWidgetComponent extends PageComponent implements OnInit, Afte
|
|||||||
this.scheduleUpdateCanvas = true;
|
this.scheduleUpdateCanvas = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,8 @@
|
|||||||
</tb-js-func>
|
</tb-js-func>
|
||||||
<tb-markdown-editor [fxShow]="!markdownWidgetSettingsForm.get('useMarkdownTextFunction').value"
|
<tb-markdown-editor [fxShow]="!markdownWidgetSettingsForm.get('useMarkdownTextFunction').value"
|
||||||
formControlName="markdownTextPattern"
|
formControlName="markdownTextPattern"
|
||||||
label="{{ 'widgets.markdown.markdown-text-pattern' | translate }}">
|
label="{{ 'widgets.markdown.markdown-text-pattern' | translate }}"
|
||||||
|
helpId="widget/editor/widget_js_markdown_pattern">
|
||||||
</tb-markdown-editor>
|
</tb-markdown-editor>
|
||||||
<tb-css formControlName="markdownCss"
|
<tb-css formControlName="markdownCss"
|
||||||
label="{{ 'widgets.markdown.markdown-css' | translate }}">
|
label="{{ 'widgets.markdown.markdown-css' | translate }}">
|
||||||
|
|||||||
@ -22,6 +22,7 @@
|
|||||||
<mat-form-field [fxShow]="!qrCodeWidgetSettingsForm.get('useQrCodeTextFunction').value">
|
<mat-form-field [fxShow]="!qrCodeWidgetSettingsForm.get('useQrCodeTextFunction').value">
|
||||||
<mat-label translate>widgets.qr-code.qr-code-text-pattern</mat-label>
|
<mat-label translate>widgets.qr-code.qr-code-text-pattern</mat-label>
|
||||||
<input required matInput formControlName="qrCodeTextPattern">
|
<input required matInput formControlName="qrCodeTextPattern">
|
||||||
|
<mat-hint>{{ 'widgets.qr-code.qr-code-text-pattern-hint' | translate }}</mat-hint>
|
||||||
<mat-error *ngIf="qrCodeWidgetSettingsForm.get('qrCodeTextPattern').hasError('required')">
|
<mat-error *ngIf="qrCodeWidgetSettingsForm.get('qrCodeTextPattern').hasError('required')">
|
||||||
{{ 'widgets.qr-code.qr-code-text-pattern-required' | translate }}
|
{{ 'widgets.qr-code.qr-code-text-pattern-required' | translate }}
|
||||||
</mat-error>
|
</mat-error>
|
||||||
|
|||||||
@ -17,25 +17,30 @@
|
|||||||
-->
|
-->
|
||||||
<div class="markdown-content" [ngClass]="{'tb-edit-mode': !readonly}"
|
<div class="markdown-content" [ngClass]="{'tb-edit-mode': !readonly}"
|
||||||
tb-fullscreen [fullscreen]="fullscreen" (fullscreenChanged)="onFullscreen()">
|
tb-fullscreen [fullscreen]="fullscreen" (fullscreenChanged)="onFullscreen()">
|
||||||
<div *ngIf="label" fxLayout="row" fxLayoutAlign="start center" style="height: 40px;">
|
<div fxLayout="row" fxLayoutAlign="start center" style="height: 40px;">
|
||||||
<label class="tb-title no-padding" [ngClass]="{'tb-error': !disabled && required && !markdownValue, 'tb-required': !disabled && required}">{{ label }}</label>
|
<label class="tb-title no-padding" [ngClass]="{'tb-error': !disabled && required && !markdownValue, 'tb-required': !disabled && required}">{{ label }}</label>
|
||||||
</div>
|
<span fxFlex></span>
|
||||||
<div [fxShow]="!readonly && !disabled" class="markdown-content-editor">
|
|
||||||
<div class="buttons-panel">
|
|
||||||
<button [fxShow]="!editorMode"
|
<button [fxShow]="!editorMode"
|
||||||
class="edit-toggle"
|
class="panel-button"
|
||||||
type="button"
|
type="button"
|
||||||
mat-button (click)="toggleEditMode()">{{ 'markdown.edit' | translate }}</button>
|
mat-button (click)="toggleEditMode()">{{ 'markdown.edit' | translate }}</button>
|
||||||
<button [fxShow]="editorMode"
|
<button [fxShow]="editorMode"
|
||||||
class="edit-toggle"
|
class="panel-button"
|
||||||
type="button"
|
type="button"
|
||||||
mat-button (click)="toggleEditMode()">{{ 'markdown.preview' | translate }}</button>
|
mat-button (click)="toggleEditMode()">{{ 'markdown.preview' | translate }}</button>
|
||||||
<button mat-button mat-icon-button (click)="fullscreen = !fullscreen"
|
<div *ngIf = "helpId" [tb-help-popup]="helpId"></div>
|
||||||
matTooltip="{{(fullscreen ? 'fullscreen.exit' : 'fullscreen.expand') | translate}}"
|
<fieldset style="width: initial">
|
||||||
matTooltipPosition="above">
|
<div matTooltip="{{(fullscreen ? 'fullscreen.exit' : 'fullscreen.expand') | translate}}"
|
||||||
|
matTooltipPosition="above"
|
||||||
|
style="border-radius: 50%"
|
||||||
|
(click)="fullscreen = !fullscreen">
|
||||||
|
<button type='button' mat-button mat-icon-button class="tb-mat-32 panel-button">
|
||||||
<mat-icon class="material-icons">{{ fullscreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>
|
<mat-icon class="material-icons">{{ fullscreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
</div>
|
||||||
|
<div [fxShow]="!readonly && !disabled" class="markdown-content-editor">
|
||||||
<div [fxShow]="editorMode" #markdownEditor class="tb-markdown-editor"></div>
|
<div [fxShow]="editorMode" #markdownEditor class="tb-markdown-editor"></div>
|
||||||
<div [fxShow]="!editorMode" class="tb-markdown-view-container">
|
<div [fxShow]="!editorMode" class="tb-markdown-view-container">
|
||||||
<tb-markdown [data]="renderValue" lineNumbers fallbackToPlainMarkdown></tb-markdown>
|
<tb-markdown [data]="renderValue" lineNumbers fallbackToPlainMarkdown></tb-markdown>
|
||||||
|
|||||||
@ -58,20 +58,15 @@
|
|||||||
overflow: auto;
|
overflow: auto;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
.buttons-panel {
|
button.panel-button {
|
||||||
position: absolute;
|
background: rgba(220, 220, 220, .35);
|
||||||
top: 5px;
|
align-items: center;
|
||||||
right: 24px;
|
vertical-align: middle;
|
||||||
z-index: 1;
|
|
||||||
button.edit-toggle {
|
|
||||||
min-width: 32px;
|
min-width: 32px;
|
||||||
min-height: 15px;
|
min-height: 15px;
|
||||||
padding: 4px;
|
padding: 4px;
|
||||||
margin: 0;
|
|
||||||
font-size: .8rem;
|
font-size: .8rem;
|
||||||
line-height: 15px;
|
line-height: 15px;
|
||||||
color: #7b7b7b;
|
color: #7b7b7b;
|
||||||
background: rgba(220, 220, 220, .35);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -40,6 +40,8 @@ export class MarkdownEditorComponent implements OnInit, ControlValueAccessor, On
|
|||||||
|
|
||||||
@Input() readonly: boolean;
|
@Input() readonly: boolean;
|
||||||
|
|
||||||
|
@Input() helpId: string;
|
||||||
|
|
||||||
@ViewChild('markdownEditor', {static: true})
|
@ViewChild('markdownEditor', {static: true})
|
||||||
markdownEditorElmRef: ElementRef;
|
markdownEditorElmRef: ElementRef;
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,68 @@
|
|||||||
|
#### Markdown pattern
|
||||||
|
|
||||||
|
<div class="divider"></div>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
The Markdown template displays the value of the first found key in the entities in the entity alias.
|
||||||
|
|
||||||
|
<div class="divider"></div>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
#### Examples
|
||||||
|
|
||||||
|
Use # to create a Markdown header. The number of characters # specifies the type of header: # - h1, ## - h2, ### - h3, etc.
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
###### Markdown/HTML card
|
||||||
|
{:copy-code}
|
||||||
|
```
|
||||||
|
###### Markdown/HTML card
|
||||||
|
|
||||||
|
<div class="divider"></div>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
Use - character to create list item. You can create nested lists separating them with tabs in the pattern:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
- Element 1
|
||||||
|
- Element 2
|
||||||
|
- Element 2.1
|
||||||
|
- Element 2.2
|
||||||
|
-Element 3
|
||||||
|
{:copy-code}
|
||||||
|
```
|
||||||
|
- Element 1
|
||||||
|
- Element 2
|
||||||
|
- Element 2.1
|
||||||
|
- Element 2.2
|
||||||
|
- Element 3
|
||||||
|
|
||||||
|
<div class="divider"></div>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
Use * character to choose style:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
- *Element 1*
|
||||||
|
- **Element 2**
|
||||||
|
- ***Element 3***
|
||||||
|
{:copy-code}
|
||||||
|
```
|
||||||
|
- *Element 1*
|
||||||
|
- **Element 2**
|
||||||
|
- ***Element 3***
|
||||||
|
|
||||||
|
<div class="divider"></div>
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
Use ${} to add some value from your key:
|
||||||
|
```markdown
|
||||||
|
- **Element 1**: ${key1Name}
|
||||||
|
- **Element 1**: ${key2Name}
|
||||||
|
- **Element 1**: ${key3Name}
|
||||||
|
{:copy-code}
|
||||||
|
```
|
||||||
|
- **Element 1**: key1Value
|
||||||
|
- **Element 2**: key2Value
|
||||||
|
- **Element 3**: key3Value
|
||||||
|
|
||||||
@ -4276,6 +4276,7 @@
|
|||||||
"qr-code": {
|
"qr-code": {
|
||||||
"use-qr-code-text-function": "Use QR code text function",
|
"use-qr-code-text-function": "Use QR code text function",
|
||||||
"qr-code-text-pattern": "QR code text pattern (for ex. '${entityName} | ${keyName} - some text.')",
|
"qr-code-text-pattern": "QR code text pattern (for ex. '${entityName} | ${keyName} - some text.')",
|
||||||
|
"qr-code-text-pattern-hint": "QR code text pattern use the value of the first found key in the entities in the entity alias.",
|
||||||
"qr-code-text-pattern-required": "QR code text pattern is required.",
|
"qr-code-text-pattern-required": "QR code text pattern is required.",
|
||||||
"qr-code-text-function": "QR code text function"
|
"qr-code-text-function": "QR code text function"
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user