2019-09-19 20:10:52 +03:00
|
|
|
<!--
|
|
|
|
|
|
2021-01-11 13:42:16 +02:00
|
|
|
Copyright © 2016-2021 The Thingsboard Authors
|
2019-09-19 20:10:52 +03:00
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
|
|
|
|
|
-->
|
|
|
|
|
<div fxFlex fxLayout="column">
|
2020-01-20 15:14:08 +02:00
|
|
|
<div fxFlex fxLayout="column" tb-fullscreen [fullscreen]="fullscreen" tb-hotkeys [hotkeys]="hotKeys" [cheatSheet]="cheatSheetComponent">
|
|
|
|
|
<tb-hotkeys-cheatsheet #cheatSheetComponent></tb-hotkeys-cheatsheet>
|
2020-04-24 15:49:53 +03:00
|
|
|
<mat-toolbar class="mat-elevation-z1 tb-edit-toolbar mat-hue-3" fxLayoutGap="16px" fxLayoutGap.lt-xl="8px">
|
2019-09-23 20:35:31 +03:00
|
|
|
<mat-form-field floatLabel="always" hideRequiredMarker class="tb-widget-title">
|
2019-09-19 20:10:52 +03:00
|
|
|
<mat-label></mat-label>
|
2019-09-23 20:35:31 +03:00
|
|
|
<input [disabled]="isReadOnly" matInput required
|
|
|
|
|
[(ngModel)]="widget.widgetName" (ngModelChange)="isDirty = true"
|
2019-09-19 20:10:52 +03:00
|
|
|
placeholder="{{ 'widget.title' | translate }}"/>
|
|
|
|
|
</mat-form-field>
|
|
|
|
|
<mat-form-field>
|
|
|
|
|
<mat-select [disabled]="isReadOnly" matInput placeholder="{{ 'widget.type' | translate }}"
|
|
|
|
|
[(ngModel)]="widget.type" (ngModelChange)="widetTypeChanged()">
|
|
|
|
|
<mat-option *ngFor="let type of allWidgetTypes" [value]="type">
|
2020-02-04 15:14:17 +02:00
|
|
|
{{ widgetTypesDataMap.get(widgetTypes[type]).name | translate }}
|
2019-09-19 20:10:52 +03:00
|
|
|
</mat-option>
|
|
|
|
|
</mat-select>
|
|
|
|
|
</mat-form-field>
|
|
|
|
|
<span fxFlex></span>
|
2020-04-21 11:53:26 +03:00
|
|
|
<button mat-button fxHide.lt-md [disabled]="!iframeWidgetEditModeInited"
|
2019-09-19 20:10:52 +03:00
|
|
|
(click)="applyWidgetScript()"
|
|
|
|
|
matTooltip="{{ 'widget.run' | translate }} (CTRL + Return)"
|
|
|
|
|
matTooltipPosition="below">
|
|
|
|
|
<mat-icon>play_arrow</mat-icon>
|
|
|
|
|
<span translate>action.run</span>
|
|
|
|
|
</button>
|
2020-04-21 11:53:26 +03:00
|
|
|
<button mat-raised-button
|
|
|
|
|
fxHide.lt-md [disabled]="(isLoading$ | async) || undoDisabled()"
|
2019-09-19 20:10:52 +03:00
|
|
|
(click)="undoWidget()"
|
|
|
|
|
matTooltip="{{ 'widget.undo' | translate }} (CTRL + Q)"
|
|
|
|
|
matTooltipPosition="below">
|
|
|
|
|
<mat-icon>undo</mat-icon>
|
|
|
|
|
<span translate>action.undo</span>
|
|
|
|
|
</button>
|
2020-04-21 11:53:26 +03:00
|
|
|
<button *ngIf="!isReadOnly" mat-raised-button
|
|
|
|
|
fxHide.lt-md [disabled]="(isLoading$ | async) || saveDisabled()"
|
2019-09-19 20:10:52 +03:00
|
|
|
(click)="saveWidget()"
|
|
|
|
|
[tb-circular-progress]="saveWidgetPending"
|
|
|
|
|
matTooltip="{{ 'widget.save' | translate }} (CTRL + S)"
|
|
|
|
|
matTooltipPosition="below">
|
|
|
|
|
<mat-icon>save</mat-icon>
|
|
|
|
|
<span translate>action.save</span>
|
|
|
|
|
</button>
|
2020-04-21 11:53:26 +03:00
|
|
|
<button mat-raised-button
|
|
|
|
|
fxHide.lt-md [disabled]="(isLoading$ | async) || saveAsDisabled()"
|
2019-09-19 20:10:52 +03:00
|
|
|
(click)="saveWidgetAs()"
|
|
|
|
|
[tb-circular-progress]="saveWidgetAsPending"
|
|
|
|
|
matTooltip="{{ 'widget.saveAs' | translate }} (Shift + CTRL + S)"
|
|
|
|
|
matTooltipPosition="below">
|
|
|
|
|
<mat-icon>save</mat-icon>
|
|
|
|
|
<span translate>action.saveAs</span>
|
|
|
|
|
</button>
|
|
|
|
|
<button mat-button
|
2020-04-24 15:49:53 +03:00
|
|
|
fxHide.lt-lg
|
2019-09-19 20:10:52 +03:00
|
|
|
(click)="fullscreen = !fullscreen"
|
|
|
|
|
matTooltip="{{ 'widget.toggle-fullscreen' | translate }} (Shift + CTRL + F)"
|
|
|
|
|
matTooltipPosition="below">
|
|
|
|
|
<mat-icon>{{ fullscreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>
|
|
|
|
|
<span translate>widget.toggle-fullscreen</span>
|
|
|
|
|
</button>
|
2020-04-24 15:49:53 +03:00
|
|
|
<button mat-icon-button fxHide fxShow.md
|
|
|
|
|
(click)="fullscreen = !fullscreen"
|
|
|
|
|
matTooltip="{{ 'widget.toggle-fullscreen' | translate }} (Shift + CTRL + F)"
|
|
|
|
|
matTooltipPosition="below">
|
|
|
|
|
<mat-icon>{{ fullscreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>
|
|
|
|
|
</button>
|
2020-04-21 11:53:26 +03:00
|
|
|
<button mat-icon-button fxHide.gt-sm
|
2019-09-19 20:10:52 +03:00
|
|
|
[matMenuTriggerFor]="widgetEditMenu">
|
|
|
|
|
<mat-icon>more_vert</mat-icon>
|
|
|
|
|
</button>
|
|
|
|
|
<mat-menu #widgetEditMenu="matMenu" xPosition="before">
|
|
|
|
|
<button mat-menu-item
|
|
|
|
|
[disabled]="!iframeWidgetEditModeInited"
|
|
|
|
|
(click)="applyWidgetScript()">
|
|
|
|
|
<mat-icon>play_arrow</mat-icon>
|
|
|
|
|
<span translate>action.run</span>
|
|
|
|
|
</button>
|
|
|
|
|
<button mat-menu-item
|
|
|
|
|
[disabled]="(isLoading$ | async) || undoDisabled()"
|
|
|
|
|
(click)="undoWidget()">
|
|
|
|
|
<mat-icon>undo</mat-icon>
|
|
|
|
|
<span translate>action.undo</span>
|
|
|
|
|
</button>
|
|
|
|
|
<button *ngIf="!isReadOnly" mat-menu-item
|
|
|
|
|
[disabled]="(isLoading$ | async) || saveDisabled()"
|
|
|
|
|
(click)="saveWidget()">
|
|
|
|
|
<mat-icon>save</mat-icon>
|
|
|
|
|
<span translate>action.save</span>
|
|
|
|
|
</button>
|
|
|
|
|
<button mat-menu-item
|
|
|
|
|
[disabled]="(isLoading$ | async) || saveAsDisabled()"
|
|
|
|
|
(click)="saveWidgetAs()">
|
|
|
|
|
<mat-icon>save</mat-icon>
|
|
|
|
|
<span translate>action.saveAs</span>
|
|
|
|
|
</button>
|
|
|
|
|
</mat-menu>
|
|
|
|
|
</mat-toolbar>
|
|
|
|
|
<div fxFlex style="position: relative;">
|
|
|
|
|
<div class="tb-editor tb-absolute-fill">
|
|
|
|
|
<div #topPanel class="tb-split tb-split-vertical">
|
|
|
|
|
<div #topLeftPanel class="tb-split tb-content">
|
|
|
|
|
<mat-tab-group selectedIndex="1" dynamicHeight="true" style="width: 100%; height: 100%;">
|
2021-02-04 19:00:28 +02:00
|
|
|
<mat-tab label="{{ 'widget.resources' | translate }}">
|
2019-09-19 20:10:52 +03:00
|
|
|
<div class="tb-resize-container" style="background-color: #fff;">
|
|
|
|
|
<div class="mat-padding">
|
|
|
|
|
<div fxFlex fxLayout="row" style="max-height: 40px;"
|
|
|
|
|
fxLayoutAlign="start center"
|
|
|
|
|
*ngFor="let resource of widget.resources; let i = index" >
|
|
|
|
|
<mat-form-field fxFlex class="mat-block resource-field" floatLabel="never"
|
2020-04-27 09:27:14 +03:00
|
|
|
style="margin: 10px 0 0 0; max-height: 40px;">
|
2019-09-19 20:10:52 +03:00
|
|
|
<input required matInput [(ngModel)]="resource.url"
|
|
|
|
|
(ngModelChange)="isDirty = true"
|
|
|
|
|
placeholder="{{ 'widget.resource-url' | translate }}"/>
|
|
|
|
|
</mat-form-field>
|
2020-07-15 12:44:16 +03:00
|
|
|
<mat-checkbox [(ngModel)]="resource.isModule"
|
|
|
|
|
(ngModelChange)="isDirty = true">
|
|
|
|
|
{{ 'widget.resource-is-module' | translate }}
|
|
|
|
|
</mat-checkbox>
|
2020-04-21 11:53:26 +03:00
|
|
|
<button mat-icon-button color="primary"
|
2019-09-19 20:10:52 +03:00
|
|
|
[disabled]="isLoading$ | async"
|
|
|
|
|
(click)="removeResource(i)"
|
|
|
|
|
matTooltip="{{'widget.remove-resource' | translate}}"
|
|
|
|
|
matTooltipPosition="above">
|
|
|
|
|
<mat-icon>close</mat-icon>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div style="margin-top: 6px;">
|
2020-04-21 11:53:26 +03:00
|
|
|
<button mat-raised-button color="primary"
|
2019-09-19 20:10:52 +03:00
|
|
|
[disabled]="isLoading$ | async"
|
|
|
|
|
(click)="addResource()"
|
|
|
|
|
matTooltip="{{'widget.add-resource' | translate}}"
|
|
|
|
|
matTooltipPosition="above">
|
|
|
|
|
<span translate>action.add</span>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</mat-tab>
|
2021-02-04 19:00:28 +02:00
|
|
|
<mat-tab label="{{ 'widget.html' | translate }}">
|
2019-09-19 20:10:52 +03:00
|
|
|
<div class="tb-resize-container" tb-fullscreen [fullscreen]="htmlFullscreen">
|
|
|
|
|
<div class="tb-editor-area-title-panel">
|
|
|
|
|
<button mat-button (click)="beautifyHtml()">
|
|
|
|
|
{{ 'widget.tidy' | translate }}
|
|
|
|
|
</button>
|
|
|
|
|
<button mat-button mat-icon-button class="tb-mat-32"
|
|
|
|
|
(click)="htmlFullscreen = !htmlFullscreen"
|
|
|
|
|
matTooltip="{{(htmlFullscreen ? 'fullscreen.exit' : 'fullscreen.expand') | translate}}"
|
|
|
|
|
matTooltipPosition="above">
|
|
|
|
|
<mat-icon>{{ htmlFullscreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div #htmlInput></div>
|
|
|
|
|
</div>
|
|
|
|
|
</mat-tab>
|
2021-02-04 19:00:28 +02:00
|
|
|
<mat-tab label="{{ 'widget.css' | translate }}">
|
2019-09-19 20:10:52 +03:00
|
|
|
<div class="tb-resize-container" tb-fullscreen [fullscreen]="cssFullscreen">
|
|
|
|
|
<div class="tb-editor-area-title-panel">
|
|
|
|
|
<button mat-button (click)="beautifyCss()">
|
|
|
|
|
{{ 'widget.tidy' | translate }}
|
|
|
|
|
</button>
|
2020-04-21 11:53:26 +03:00
|
|
|
<button mat-icon-button class="tb-mat-32"
|
2019-09-19 20:10:52 +03:00
|
|
|
(click)="cssFullscreen = !cssFullscreen"
|
|
|
|
|
matTooltip="{{(cssFullscreen ? 'fullscreen.exit' : 'fullscreen.expand') | translate}}"
|
|
|
|
|
matTooltipPosition="above">
|
|
|
|
|
<mat-icon>{{ cssFullscreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div #cssInput></div>
|
|
|
|
|
</div>
|
|
|
|
|
</mat-tab>
|
|
|
|
|
</mat-tab-group>
|
|
|
|
|
</div>
|
|
|
|
|
<div #topRightPanel class="tb-split tb-content">
|
|
|
|
|
<mat-tab-group dynamicHeight="true" style="width: 100%; height: 100%;">
|
2021-02-04 19:00:28 +02:00
|
|
|
<mat-tab label="{{ 'widget.settings-schema' | translate }}">
|
2019-09-19 20:10:52 +03:00
|
|
|
<div class="tb-resize-container" tb-fullscreen [fullscreen]="jsonSettingsFullscreen">
|
|
|
|
|
<div class="tb-editor-area-title-panel">
|
|
|
|
|
<button mat-button (click)="beautifyJson()">
|
|
|
|
|
{{ 'widget.tidy' | translate }}
|
|
|
|
|
</button>
|
2020-04-21 11:53:26 +03:00
|
|
|
<button mat-icon-button class="tb-mat-32"
|
2019-09-19 20:10:52 +03:00
|
|
|
(click)="jsonSettingsFullscreen = !jsonSettingsFullscreen"
|
|
|
|
|
matTooltip="{{(jsonSettingsFullscreen ? 'fullscreen.exit' : 'fullscreen.expand') | translate}}"
|
|
|
|
|
matTooltipPosition="above">
|
|
|
|
|
<mat-icon>{{ jsonSettingsFullscreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div #settingsJsonInput></div>
|
|
|
|
|
</div>
|
|
|
|
|
</mat-tab>
|
2021-02-04 19:00:28 +02:00
|
|
|
<mat-tab label="{{ 'widget.datakey-settings-schema' | translate }}">
|
2019-09-19 20:10:52 +03:00
|
|
|
<div class="tb-resize-container" tb-fullscreen [fullscreen]="jsonDataKeySettingsFullscreen">
|
|
|
|
|
<div class="tb-editor-area-title-panel">
|
|
|
|
|
<button mat-button (click)="beautifyDataKeyJson()">
|
|
|
|
|
{{ 'widget.tidy' | translate }}
|
|
|
|
|
</button>
|
2020-04-21 11:53:26 +03:00
|
|
|
<button mat-icon-button class="tb-mat-32"
|
2019-09-19 20:10:52 +03:00
|
|
|
(click)="jsonDataKeySettingsFullscreen = !jsonDataKeySettingsFullscreen"
|
|
|
|
|
matTooltip="{{(jsonDataKeySettingsFullscreen ? 'fullscreen.exit' : 'fullscreen.expand') | translate}}"
|
|
|
|
|
matTooltipPosition="above">
|
|
|
|
|
<mat-icon>{{ jsonDataKeySettingsFullscreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div #dataKeySettingsJsonInput></div>
|
|
|
|
|
</div>
|
|
|
|
|
</mat-tab>
|
2021-02-04 19:00:28 +02:00
|
|
|
<mat-tab label="{{ 'widget.widget-settings' | translate }}">
|
|
|
|
|
<div class="tb-resize-container" style="background-color: #fff;">
|
|
|
|
|
<div class="mat-padding">
|
|
|
|
|
<tb-image-input fxFlex label="{{'widget.image-preview' | translate}}"
|
|
|
|
|
maxSizeByte="524288"
|
|
|
|
|
[(ngModel)]="widget.image"
|
|
|
|
|
(ngModelChange)="isDirty = true" >
|
|
|
|
|
</tb-image-input>
|
|
|
|
|
<mat-form-field class="mat-block">
|
|
|
|
|
<mat-label translate>widget.description</mat-label>
|
|
|
|
|
<textarea matInput #descriptionInput
|
|
|
|
|
[(ngModel)]="widget.description"
|
|
|
|
|
(ngModelChange)="isDirty = true"
|
|
|
|
|
rows="2" maxlength="255"></textarea>
|
|
|
|
|
<mat-hint align="end">{{descriptionInput.value?.length || 0}}/255</mat-hint>
|
|
|
|
|
</mat-form-field>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</mat-tab>
|
2019-09-19 20:10:52 +03:00
|
|
|
</mat-tab-group>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div #bottomPanel class="tb-split tb-split-vertical">
|
|
|
|
|
<div #javascriptPanel class="tb-split tb-content" tb-toast toastTarget="javascriptPanel">
|
|
|
|
|
<div class="tb-resize-container" tb-fullscreen [fullscreen]="javascriptFullscreen">
|
|
|
|
|
<div class="tb-editor-area-title-panel">
|
|
|
|
|
<label translate>widget.javascript</label>
|
|
|
|
|
<button mat-button (click)="beautifyJs()">
|
|
|
|
|
{{ 'widget.tidy' | translate }}
|
|
|
|
|
</button>
|
2020-04-21 11:53:26 +03:00
|
|
|
<button mat-icon-button class="tb-mat-32"
|
2019-09-19 20:10:52 +03:00
|
|
|
(click)="javascriptFullscreen = !javascriptFullscreen"
|
|
|
|
|
matTooltip="{{(javascriptFullscreen ? 'fullscreen.exit' : 'fullscreen.expand') | translate}}"
|
|
|
|
|
matTooltipPosition="above">
|
|
|
|
|
<mat-icon>{{ javascriptFullscreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div #javascriptInput></div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<div #framePanel class="tb-split tb-content" style="overflow-y: hidden; position: relative;">
|
|
|
|
|
<div class="mat-content tb-progress-cover" fxFlex fxLayout="column" fxLayoutAlign="center center"
|
|
|
|
|
*ngIf="!iframeWidgetEditModeInited">
|
|
|
|
|
<mat-spinner diameter="100" mode="indeterminate" color="warn"></mat-spinner>
|
|
|
|
|
</div>
|
|
|
|
|
<div tb-fullscreen [fullscreen]="iFrameFullscreen" style="width: 100%; height: 100%;">
|
|
|
|
|
<iframe #widgetIFrame frameborder="0" height="100%" width="100%"></iframe>
|
2019-09-23 20:35:31 +03:00
|
|
|
<div style="position: absolute; top: 10px; left: 10px; bottom: initial;">
|
2020-04-21 11:53:26 +03:00
|
|
|
<button mat-icon-button
|
2019-09-23 20:35:31 +03:00
|
|
|
class="tb-fullscreen-button-style"
|
|
|
|
|
(click)="iFrameFullscreen = !iFrameFullscreen"
|
|
|
|
|
matTooltip="{{(iFrameFullscreen ? 'fullscreen.exit' : 'fullscreen.expand') | translate}}"
|
|
|
|
|
matTooltipPosition="above">
|
|
|
|
|
<mat-icon>{{ iFrameFullscreen ? 'fullscreen_exit' : 'fullscreen' }}</mat-icon>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
2019-09-19 20:10:52 +03:00
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|