thingsboard-aplcache

Improve Entity View UI

10/16/2018 8:46:34 AM

Details

diff --git a/ui/src/app/entity-view/add-entity-view.tpl.html b/ui/src/app/entity-view/add-entity-view.tpl.html
index 48a1788..ebf1f1d 100644
--- a/ui/src/app/entity-view/add-entity-view.tpl.html
+++ b/ui/src/app/entity-view/add-entity-view.tpl.html
@@ -15,7 +15,7 @@
     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()">
 	    <md-toolbar>
 	      <div class="md-toolbar-tools">
diff --git a/ui/src/app/entity-view/entity-view.directive.js b/ui/src/app/entity-view/entity-view.directive.js
index d183053..25377f4 100644
--- a/ui/src/app/entity-view/entity-view.directive.js
+++ b/ui/src/app/entity-view/entity-view.directive.js
@@ -13,6 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+import './entity-view.scss';
+
 /* eslint-disable import/no-unresolved, import/default */
 
 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 */
 
 /*@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) {
     var linker = function (scope, element) {
         var template = $templateCache.get(entityViewFieldsetTemplate);
         element.html(template);
 
+        scope.attributesPanelId = (Math.random()*1000).toFixed(0);
+        scope.timeseriesPanelId = (Math.random()*1000).toFixed(0);
+        scope.$mdExpansionPanel = $mdExpansionPanel;
+
         scope.types = types;
         scope.isAssignedToCustomer = false;
         scope.isPublic = false;
diff --git a/ui/src/app/entity-view/entity-view.scss b/ui/src/app/entity-view/entity-view.scss
new file mode 100644
index 0000000..7b16b4a
--- /dev/null
+++ b/ui/src/app/entity-view/entity-view.scss
@@ -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;
+  }
+}
diff --git a/ui/src/app/entity-view/entity-view-fieldset.tpl.html b/ui/src/app/entity-view/entity-view-fieldset.tpl.html
index 74d1e33..140c199 100644
--- a/ui/src/app/entity-view/entity-view-fieldset.tpl.html
+++ b/ui/src/app/entity-view/entity-view-fieldset.tpl.html
@@ -60,7 +60,7 @@
                 entity-type="types.entityType.entityView">
         </tb-entity-subtype-autocomplete>
         <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"
                               the-form="theForm"
                               tb-required="true"
@@ -68,110 +68,145 @@
                               ng-model="entityView.entityId">
             </tb-entity-select>
         </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">
             <label translate>entity-view.description</label>
             <textarea ng-model="entityView.additionalInfo.description" rows="2"></textarea>
         </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>
 </md-content>
diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json
index ccfcf65..48e578e 100644
--- a/ui/src/app/locale/locale.constant-en_US.json
+++ b/ui/src/app/locale/locale.constant-en_US.json
@@ -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}}",
         "select-entity-view": "Select entity view",
         "make-public": "Make entity view public",
+        "start-date": "Start date",
         "start-ts": "Start time",
+        "end-date": "End date",
         "end-ts": "End time",
         "date-limits": "Date limits",
         "client-attributes": "Client attributes",
@@ -849,7 +851,11 @@
         "shared-attributes-placeholder": "Shared attributes",
         "server-attributes-placeholder": "Server attributes",
         "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-type": "Event type",