Improve Entity View UI

This commit is contained in:
Igor Kulikov 2018-10-16 14:46:34 +03:00
parent acb9486835
commit cc1ad23c4e
5 changed files with 200 additions and 105 deletions

View File

@ -15,7 +15,7 @@
limitations under the License. limitations under the License.
--> -->
<md-dialog aria-label="{{ 'entity-view.add' | translate }}" tb-help="'entityViews'" help-container-id="help-container"> <md-dialog aria-label="{{ 'entity-view.add' | translate }}" style="width: 800px;" tb-help="'entityViews'" help-container-id="help-container">
<form name="theForm" ng-submit="vm.add()"> <form name="theForm" ng-submit="vm.add()">
<md-toolbar> <md-toolbar>
<div class="md-toolbar-tools"> <div class="md-toolbar-tools">

View File

@ -60,7 +60,7 @@
entity-type="types.entityType.entityView"> entity-type="types.entityType.entityView">
</tb-entity-subtype-autocomplete> </tb-entity-subtype-autocomplete>
<section layout="column"> <section layout="column">
<label translate class="tb-title no-padding">entity-view.related-entity</label> <label translate class="tb-title no-padding">entity-view.target-entity</label>
<tb-entity-select flex ng-disabled="!isEdit" <tb-entity-select flex ng-disabled="!isEdit"
the-form="theForm" the-form="theForm"
tb-required="true" tb-required="true"
@ -68,110 +68,145 @@
ng-model="entityView.entityId"> ng-model="entityView.entityId">
</tb-entity-select> </tb-entity-select>
</section> </section>
<md-expansion-panel-group class="tb-entity-view-panel-group" ng-class="{'disabled': $root.loading || !isEdit}"
auto-expand="true"
multiple="true"
md-component-id="attributesPanelGroup">
<md-expansion-panel md-component-id="{{attributesPanelId}}">
<md-expansion-panel-collapsed>
<div class="tb-panel-title">{{ 'entity-view.attributes-propagation' | translate }}</div>
<span flex></span>
<md-expansion-panel-icon></md-expansion-panel-icon>
</md-expansion-panel-collapsed>
<md-expansion-panel-expanded>
<md-expansion-panel-header ng-click="$mdExpansionPanel(attributesPanelId).collapse()">
<div class="tb-panel-title">{{ 'entity-view.attributes-propagation' | translate }}</div>
<span flex></span>
<md-expansion-panel-icon></md-expansion-panel-icon>
</md-expansion-panel-header>
<md-expansion-panel-content>
<div translate class="tb-hint">entity-view.attributes-propagation-hint</div>
<label translate class="tb-title no-padding">entity-view.client-attributes</label>
<md-chips style="padding-bottom: 15px;"
ng-required="false"
readonly="!isEdit"
ng-model="entityView.keys.attributes.cs"
placeholder="{{'entity-view.client-attributes-placeholder' | translate}}"
md-separator-keys="separatorKeys">
<md-autocomplete
md-no-cache="true"
id="ca_datakey"
md-selected-item="selectedAttributeDataKey"
md-search-text="attributeDataKeySearchText"
md-items="item in dataKeysSearch(attributeDataKeySearchText, types.dataKeyType.attribute)"
md-item-text="item.name"
md-min-length="0"
placeholder="{{'entity-view.client-attributes-placeholder' | translate }}"
md-menu-class="tb-attribute-datakey-autocomplete">
<span md-highlight-text="attributeDataKeySearchText" md-highlight-flags="^i">{{item}}</span>
</md-autocomplete>
</md-chips>
<label translate class="tb-title no-padding">entity-view.shared-attributes</label>
<md-chips style="padding-bottom: 15px;"
ng-required="false"
readonly="!isEdit"
ng-model="entityView.keys.attributes.sh"
placeholder="{{'entity-view.shared-attributes-placeholder' | translate}}"
md-separator-keys="separatorKeys">
<md-autocomplete
md-no-cache="true"
id="sh_datakey"
md-selected-item="selectedAttributeDataKey"
md-search-text="attributeDataKeySearchText"
md-items="item in dataKeysSearch(attributeDataKeySearchText, types.dataKeyType.attribute)"
md-item-text="item.name"
md-min-length="0"
placeholder="{{'entity-view.server-attributes-placeholder' | translate }}"
md-menu-class="tb-attribute-datakey-autocomplete">
<span md-highlight-text="attributeDataKeySearchText" md-highlight-flags="^i">{{item}}</span>
</md-autocomplete>
</md-chips>
<label translate class="tb-title no-padding">entity-view.server-attributes</label>
<md-chips style="padding-bottom: 15px;"
ng-required="false"
readonly="!isEdit"
ng-model="entityView.keys.attributes.ss"
placeholder="{{'entity-view.server-attributes-placeholder' | translate}}"
md-separator-keys="separatorKeys">
<md-autocomplete
md-no-cache="true"
id="ss_datakey"
md-selected-item="selectedAttributeDataKey"
md-search-text="attributeDataKeySearchText"
md-items="item in dataKeysSearch(attributeDataKeySearchText, types.dataKeyType.attribute)"
md-item-text="item.name"
md-min-length="0"
placeholder="{{'entity-view.server-attributes-placeholder' | translate }}"
md-menu-class="tb-attribute-datakey-autocomplete">
<span md-highlight-text="attributeDataKeySearchText" md-highlight-flags="^i">{{item}}</span>
</md-autocomplete>
</md-chips>
</md-expansion-panel-content>
</md-expansion-panel-expanded>
</md-expansion-panel>
<md-expansion-panel md-component-id="{{timeseriesPanelId}}">
<md-expansion-panel-collapsed>
<div class="tb-panel-title">{{ 'entity-view.timeseries-data' | translate }}</div>
<span flex></span>
<md-expansion-panel-icon></md-expansion-panel-icon>
</md-expansion-panel-collapsed>
<md-expansion-panel-expanded>
<md-expansion-panel-header ng-click="$mdExpansionPanel(timeseriesPanelId).collapse()">
<div class="tb-panel-title">{{ 'entity-view.timeseries-data' | translate }}</div>
<span flex></span>
<md-expansion-panel-icon></md-expansion-panel-icon>
</md-expansion-panel-header>
<md-expansion-panel-content>
<div translate class="tb-hint">entity-view.timeseries-data-hint</div>
<label translate class="tb-title no-padding">entity-view.timeseries</label>
<md-chips ng-required="false"
readonly="!isEdit"
ng-model="entityView.keys.timeseries"
placeholder="{{'entity-view.timeseries-placeholder' | translate}}"
md-separator-keys="separatorKeys">
<md-autocomplete
md-no-cache="true"
id="timeseries_datakey"
md-selected-item="selectedTimeseriesDataKey"
md-search-text="timeseriesDataKeySearchText"
md-items="item in dataKeysSearch(timeseriesDataKeySearchText, types.dataKeyType.timeseries)"
md-item-text="item.name"
md-min-length="0"
placeholder="{{'entity-view.timeseries-placeholder' | translate }}"
md-menu-class="tb-timeseries-datakey-autocomplete">
<span md-highlight-text="timeseriesDataKeySearchText" md-highlight-flags="^i">{{item}}</span>
</md-autocomplete>
</md-chips>
</md-expansion-panel-content>
</md-expansion-panel-expanded>
</md-expansion-panel>
</md-expansion-panel-group>
<section layout="row" layout-align="start start">
<mdp-date-picker ng-model="startTimeMs"
mdp-max-date="maxStartTimeMs"
mdp-placeholder="{{ 'entity-view.start-date' | translate }}"></mdp-date-picker>
<mdp-time-picker ng-model="startTimeMs"
mdp-max-date="maxStartTimeMs"
mdp-placeholder="{{ 'entity-view.start-ts' | translate }}"
mdp-auto-switch="true"></mdp-time-picker>
</section>
<section layout="row" layout-align="start start">
<mdp-date-picker ng-model="endTimeMs"
mdp-min-date="minEndTimeMs"
mdp-placeholder="{{ 'entity-view.end-date' | translate }}"></mdp-date-picker>
<mdp-time-picker ng-model="endTimeMs"
mdp-min-date="minEndTimeMs"
mdp-placeholder="{{ 'entity-view.end-ts' | translate }}"
mdp-auto-switch="true"></mdp-time-picker>
</section>
<md-input-container class="md-block"> <md-input-container class="md-block">
<label translate>entity-view.description</label> <label translate>entity-view.description</label>
<textarea ng-model="entityView.additionalInfo.description" rows="2"></textarea> <textarea ng-model="entityView.additionalInfo.description" rows="2"></textarea>
</md-input-container> </md-input-container>
<section layout="column">
<label translate class="tb-title no-padding">entity-view.client-attributes</label>
<md-chips style="padding-bottom: 15px;"
ng-required="false"
readonly="!isEdit"
ng-model="entityView.keys.attributes.cs"
placeholder="{{'entity-view.client-attributes-placeholder' | translate}}"
md-separator-keys="separatorKeys">
<md-autocomplete
md-no-cache="true"
id="ca_datakey"
md-selected-item="selectedAttributeDataKey"
md-search-text="attributeDataKeySearchText"
md-items="item in dataKeysSearch(attributeDataKeySearchText, types.dataKeyType.attribute)"
md-item-text="item.name"
md-min-length="0"
placeholder="{{'entity-view.client-attributes-placeholder' | translate }}"
md-menu-class="tb-attribute-datakey-autocomplete">
<span md-highlight-text="attributeDataKeySearchText" md-highlight-flags="^i">{{item}}</span>
</md-autocomplete>
</md-chips>
<label translate class="tb-title no-padding">entity-view.shared-attributes</label>
<md-chips style="padding-bottom: 15px;"
ng-required="false"
readonly="!isEdit"
ng-model="entityView.keys.attributes.sh"
placeholder="{{'entity-view.shared-attributes-placeholder' | translate}}"
md-separator-keys="separatorKeys">
<md-autocomplete
md-no-cache="true"
id="sh_datakey"
md-selected-item="selectedAttributeDataKey"
md-search-text="attributeDataKeySearchText"
md-items="item in dataKeysSearch(attributeDataKeySearchText, types.dataKeyType.attribute)"
md-item-text="item.name"
md-min-length="0"
placeholder="{{'entity-view.server-attributes-placeholder' | translate }}"
md-menu-class="tb-attribute-datakey-autocomplete">
<span md-highlight-text="attributeDataKeySearchText" md-highlight-flags="^i">{{item}}</span>
</md-autocomplete>
</md-chips>
<label translate class="tb-title no-padding">entity-view.server-attributes</label>
<md-chips style="padding-bottom: 15px;"
ng-required="false"
readonly="!isEdit"
ng-model="entityView.keys.attributes.ss"
placeholder="{{'entity-view.server-attributes-placeholder' | translate}}"
md-separator-keys="separatorKeys">
<md-autocomplete
md-no-cache="true"
id="ss_datakey"
md-selected-item="selectedAttributeDataKey"
md-search-text="attributeDataKeySearchText"
md-items="item in dataKeysSearch(attributeDataKeySearchText, types.dataKeyType.attribute)"
md-item-text="item.name"
md-min-length="0"
placeholder="{{'entity-view.server-attributes-placeholder' | translate }}"
md-menu-class="tb-attribute-datakey-autocomplete">
<span md-highlight-text="attributeDataKeySearchText" md-highlight-flags="^i">{{item}}</span>
</md-autocomplete>
</md-chips>
<label translate class="tb-title no-padding">entity-view.timeseries</label>
<md-chips ng-required="false"
readonly="!isEdit"
ng-model="entityView.keys.timeseries"
placeholder="{{'entity-view.timeseries-placeholder' | translate}}"
md-separator-keys="separatorKeys">
<md-autocomplete
md-no-cache="true"
id="timeseries_datakey"
md-selected-item="selectedTimeseriesDataKey"
md-search-text="timeseriesDataKeySearchText"
md-items="item in dataKeysSearch(timeseriesDataKeySearchText, types.dataKeyType.timeseries)"
md-item-text="item.name"
md-min-length="0"
placeholder="{{'entity-view.timeseries-placeholder' | translate }}"
md-menu-class="tb-timeseries-datakey-autocomplete">
<span md-highlight-text="timeseriesDataKeySearchText" md-highlight-flags="^i">{{item}}</span>
</md-autocomplete>
</md-chips>
</section>
<section layout="column">
<section layout="row" layout-align="start start">
<mdp-date-picker ng-model="startTimeMs"
mdp-max-date="maxStartTimeMs"
mdp-placeholder="{{ 'entity-view.start-ts' | translate }}"></mdp-date-picker>
<mdp-time-picker ng-model="startTimeMs"
mdp-max-date="maxStartTimeMs"
mdp-placeholder="{{ 'entity-view.start-ts' | translate }}"
mdp-auto-switch="true"></mdp-time-picker>
</section>
<section layout="row" layout-align="start start">
<mdp-date-picker ng-model="endTimeMs"
mdp-min-date="minEndTimeMs"
mdp-placeholder="{{ 'entity-view.end-ts' | translate }}"></mdp-date-picker>
<mdp-time-picker ng-model="endTimeMs"
mdp-min-date="minEndTimeMs"
mdp-placeholder="{{ 'entity-view.end-ts' | translate }}"
mdp-auto-switch="true"></mdp-time-picker>
</section>
</section>
</fieldset> </fieldset>
</md-content> </md-content>

View File

@ -13,6 +13,9 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
import './entity-view.scss';
/* eslint-disable import/no-unresolved, import/default */ /* eslint-disable import/no-unresolved, import/default */
import entityViewFieldsetTemplate from './entity-view-fieldset.tpl.html'; import entityViewFieldsetTemplate from './entity-view-fieldset.tpl.html';
@ -20,12 +23,16 @@ import entityViewFieldsetTemplate from './entity-view-fieldset.tpl.html';
/* eslint-enable import/no-unresolved, import/default */ /* eslint-enable import/no-unresolved, import/default */
/*@ngInject*/ /*@ngInject*/
export default function EntityViewDirective($q, $compile, $templateCache, $filter, toast, $translate, $mdConstant, export default function EntityViewDirective($q, $compile, $templateCache, $filter, toast, $translate, $mdConstant, $mdExpansionPanel,
types, clipboardService, entityViewService, customerService, entityService) { types, clipboardService, entityViewService, customerService, entityService) {
var linker = function (scope, element) { var linker = function (scope, element) {
var template = $templateCache.get(entityViewFieldsetTemplate); var template = $templateCache.get(entityViewFieldsetTemplate);
element.html(template); element.html(template);
scope.attributesPanelId = (Math.random()*1000).toFixed(0);
scope.timeseriesPanelId = (Math.random()*1000).toFixed(0);
scope.$mdExpansionPanel = $mdExpansionPanel;
scope.types = types; scope.types = types;
scope.isAssignedToCustomer = false; scope.isAssignedToCustomer = false;
scope.isPublic = false; scope.isPublic = false;

View File

@ -0,0 +1,47 @@
/**
* Copyright © 2016-2018 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 "../../scss/constants";
.tb-entity-view-panel-group {
.tb-panel-title {
min-width: 90px;
user-select: none;
@media (min-width: $layout-breakpoint-sm) {
min-width: 180px;
}
}
.tb-panel-prompt {
overflow: hidden;
font-size: 14px;
color: rgba(0, 0, 0, .87);
text-overflow: ellipsis;
white-space: nowrap;
}
&.disabled {
.tb-panel-title,
.tb-panel-prompt {
color: rgba(0, 0, 0, .38);
}
}
md-icon.md-expansion-panel-icon {
margin-right: 0;
}
}

View File

@ -838,7 +838,9 @@
"unable-entity-view-device-alias-text": "Device alias '{{entityViewAlias}}' can't be deleted as it used by the following widget(s):<br/>{{widgetsList}}", "unable-entity-view-device-alias-text": "Device alias '{{entityViewAlias}}' can't be deleted as it used by the following widget(s):<br/>{{widgetsList}}",
"select-entity-view": "Select entity view", "select-entity-view": "Select entity view",
"make-public": "Make entity view public", "make-public": "Make entity view public",
"start-date": "Start date",
"start-ts": "Start time", "start-ts": "Start time",
"end-date": "End date",
"end-ts": "End time", "end-ts": "End time",
"date-limits": "Date limits", "date-limits": "Date limits",
"client-attributes": "Client attributes", "client-attributes": "Client attributes",
@ -849,7 +851,11 @@
"shared-attributes-placeholder": "Shared attributes", "shared-attributes-placeholder": "Shared attributes",
"server-attributes-placeholder": "Server attributes", "server-attributes-placeholder": "Server attributes",
"timeseries-placeholder": "Timeseries", "timeseries-placeholder": "Timeseries",
"related-entity": "Related entity" "target-entity": "Target entity",
"attributes-propagation": "Attributes propagation",
"attributes-propagation-hint": "Entity View will automatically copy specified attributes from Target Entity each time you save or update this entity view. For performance reasons target entity attributes are not propagated to entity view on each attribute change. You can enable automatic propagation by configuring \"copy to view\" rule node in your rule chain and linking \"Post attributes\" and \"Attributes Updated\" messages to the new rule node.",
"timeseries-data": "Timeseries data",
"timeseries-data-hint": "Configure timeseries data keys of the target entity that will be accessible to the entity view. This timeseries data is read-only."
}, },
"event": { "event": {
"event-type": "Event type", "event-type": "Event type",