Showing
27 changed files
with
349 additions
and
72 deletions
@@ -74,8 +74,8 @@ | @@ -74,8 +74,8 @@ | ||
74 | <input ng-model="vm.alarmStatus" readonly> | 74 | <input ng-model="vm.alarmStatus" readonly> |
75 | </md-input-container> | 75 | </md-input-container> |
76 | </div> | 76 | </div> |
77 | - <div ng-if="vm.displayDetails" class="md-caption" style="padding-left: 3px; padding-bottom: 10px; color: rgba(0,0,0,0.57);" translate>alarm.details</div> | ||
78 | - <div ng-if="vm.displayDetails" flex class="tb-alarm-details-panel" layout="column"> | 77 | + <div ng-show="vm.displayDetails" class="md-caption" style="padding-left: 3px; padding-bottom: 10px; color: rgba(0,0,0,0.57);" translate>alarm.details</div> |
78 | + <div ng-show="vm.displayDetails" flex class="tb-alarm-details-panel" layout="column"> | ||
79 | <div flex id="tb-alarm-details" readonly | 79 | <div flex id="tb-alarm-details" readonly |
80 | ui-ace="vm.alarmDetailsOptions" | 80 | ui-ace="vm.alarmDetailsOptions" |
81 | ng-model="vm.alarmDetails"> | 81 | ng-model="vm.alarmDetails"> |
1 | +/* | ||
2 | + * Copyright © 2016-2017 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +/*@ngInject*/ | ||
18 | +export default function DashboardSelectPanelController(mdPanelRef, $scope, $filter, dashboards, dashboardId, onDashboardSelected) { | ||
19 | + | ||
20 | + var vm = this; | ||
21 | + vm._mdPanelRef = mdPanelRef; | ||
22 | + vm.dashboards = dashboards; | ||
23 | + vm.dashboardId = dashboardId; | ||
24 | + | ||
25 | + vm.dashboardSelected = dashboardSelected; | ||
26 | + | ||
27 | + function dashboardSelected(dashboardId) { | ||
28 | + if (onDashboardSelected) { | ||
29 | + onDashboardSelected(dashboardId); | ||
30 | + } | ||
31 | + } | ||
32 | +} |
1 | +<!-- | ||
2 | + | ||
3 | + Copyright © 2016-2017 The Thingsboard Authors | ||
4 | + | ||
5 | + Licensed under the Apache License, Version 2.0 (the "License"); | ||
6 | + you may not use this file except in compliance with the License. | ||
7 | + You may obtain a copy of the License at | ||
8 | + | ||
9 | + http://www.apache.org/licenses/LICENSE-2.0 | ||
10 | + | ||
11 | + Unless required by applicable law or agreed to in writing, software | ||
12 | + distributed under the License is distributed on an "AS IS" BASIS, | ||
13 | + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
14 | + See the License for the specific language governing permissions and | ||
15 | + limitations under the License. | ||
16 | + | ||
17 | +--> | ||
18 | +<md-content flex layout="column"> | ||
19 | + <section flex layout="column"> | ||
20 | + <md-content flex class="md-padding" layout="column"> | ||
21 | + <md-input-container flex> | ||
22 | + <label>{{ 'dashboard.select-dashboard' | translate }}</label> | ||
23 | + <md-select ng-model="vm.dashboardId" ng-change="vm.dashboardSelected(vm.dashboardId)"> | ||
24 | + <md-option ng-repeat="dashboard in vm.dashboards" ng-value="dashboard.id.id"> | ||
25 | + {{dashboard.title}} | ||
26 | + </md-option> | ||
27 | + </md-select> | ||
28 | + </md-input-container> | ||
29 | + </md-content> | ||
30 | + </section> | ||
31 | +</md-content> |
@@ -21,16 +21,20 @@ import thingsboardApiUser from '../api/user.service'; | @@ -21,16 +21,20 @@ import thingsboardApiUser from '../api/user.service'; | ||
21 | /* eslint-disable import/no-unresolved, import/default */ | 21 | /* eslint-disable import/no-unresolved, import/default */ |
22 | 22 | ||
23 | import dashboardSelectTemplate from './dashboard-select.tpl.html'; | 23 | import dashboardSelectTemplate from './dashboard-select.tpl.html'; |
24 | +import dashboardSelectPanelTemplate from './dashboard-select-panel.tpl.html'; | ||
24 | 25 | ||
25 | /* eslint-enable import/no-unresolved, import/default */ | 26 | /* eslint-enable import/no-unresolved, import/default */ |
26 | 27 | ||
28 | +import DashboardSelectPanelController from './dashboard-select-panel.controller'; | ||
29 | + | ||
27 | 30 | ||
28 | export default angular.module('thingsboard.directives.dashboardSelect', [thingsboardApiDashboard, thingsboardApiUser]) | 31 | export default angular.module('thingsboard.directives.dashboardSelect', [thingsboardApiDashboard, thingsboardApiUser]) |
29 | .directive('tbDashboardSelect', DashboardSelect) | 32 | .directive('tbDashboardSelect', DashboardSelect) |
33 | + .controller('DashboardSelectPanelController', DashboardSelectPanelController) | ||
30 | .name; | 34 | .name; |
31 | 35 | ||
32 | /*@ngInject*/ | 36 | /*@ngInject*/ |
33 | -function DashboardSelect($compile, $templateCache, $q, types, dashboardService, userService) { | 37 | +function DashboardSelect($compile, $templateCache, $q, $mdMedia, $mdPanel, $document, types, dashboardService, userService) { |
34 | 38 | ||
35 | var linker = function (scope, element, attrs, ngModelCtrl) { | 39 | var linker = function (scope, element, attrs, ngModelCtrl) { |
36 | var template = $templateCache.get(dashboardSelectTemplate); | 40 | var template = $templateCache.get(dashboardSelectTemplate); |
@@ -74,6 +78,59 @@ function DashboardSelect($compile, $templateCache, $q, types, dashboardService, | @@ -74,6 +78,59 @@ function DashboardSelect($compile, $templateCache, $q, types, dashboardService, | ||
74 | scope.updateView(); | 78 | scope.updateView(); |
75 | }); | 79 | }); |
76 | 80 | ||
81 | + scope.openDashboardSelectPanel = function (event) { | ||
82 | + if (scope.disabled) { | ||
83 | + return; | ||
84 | + } | ||
85 | + var position; | ||
86 | + var panelHeight = $mdMedia('min-height: 350px') ? 250 : 150; | ||
87 | + var panelWidth = 300; | ||
88 | + var offset = element[0].getBoundingClientRect(); | ||
89 | + var bottomY = offset.bottom - $(window).scrollTop(); //eslint-disable-line | ||
90 | + var leftX = offset.left - $(window).scrollLeft(); //eslint-disable-line | ||
91 | + var yPosition; | ||
92 | + var xPosition; | ||
93 | + if (bottomY + panelHeight > $( window ).height()) { //eslint-disable-line | ||
94 | + yPosition = $mdPanel.yPosition.ABOVE; | ||
95 | + } else { | ||
96 | + yPosition = $mdPanel.yPosition.BELOW; | ||
97 | + } | ||
98 | + if (leftX + panelWidth > $( window ).width()) { //eslint-disable-line | ||
99 | + xPosition = $mdPanel.xPosition.CENTER; | ||
100 | + } else { | ||
101 | + xPosition = $mdPanel.xPosition.ALIGN_START; | ||
102 | + } | ||
103 | + position = $mdPanel.newPanelPosition() | ||
104 | + .relativeTo(element) | ||
105 | + .addPanelPosition(xPosition, yPosition); | ||
106 | + var config = { | ||
107 | + attachTo: angular.element($document[0].body), | ||
108 | + controller: 'DashboardSelectPanelController', | ||
109 | + controllerAs: 'vm', | ||
110 | + templateUrl: dashboardSelectPanelTemplate, | ||
111 | + panelClass: 'tb-dashboard-select-panel', | ||
112 | + position: position, | ||
113 | + fullscreen: false, | ||
114 | + locals: { | ||
115 | + dashboards: scope.dashboards, | ||
116 | + dashboardId: scope.dashboardId, | ||
117 | + onDashboardSelected: (dashboardId) => { | ||
118 | + if (scope.panelRef) { | ||
119 | + scope.panelRef.close(); | ||
120 | + } | ||
121 | + scope.dashboardId = dashboardId; | ||
122 | + } | ||
123 | + }, | ||
124 | + openFrom: event, | ||
125 | + clickOutsideToClose: true, | ||
126 | + escapeToClose: true, | ||
127 | + focusOnOpen: false | ||
128 | + }; | ||
129 | + $mdPanel.open(config).then(function(result) { | ||
130 | + scope.panelRef = result; | ||
131 | + }); | ||
132 | + } | ||
133 | + | ||
77 | $compile(element.contents())(scope); | 134 | $compile(element.contents())(scope); |
78 | } | 135 | } |
79 | 136 |
@@ -14,8 +14,48 @@ | @@ -14,8 +14,48 @@ | ||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | +@import '../../scss/constants'; | ||
18 | + | ||
17 | tb-dashboard-select { | 19 | tb-dashboard-select { |
20 | + min-width: 52px; | ||
18 | md-select { | 21 | md-select { |
19 | pointer-events: all; | 22 | pointer-events: all; |
23 | + max-width: 300px; | ||
24 | + } | ||
25 | +} | ||
26 | + | ||
27 | +.tb-dashboard-select { | ||
28 | + min-height: 32px; | ||
29 | + span { | ||
30 | + pointer-events: all; | ||
31 | + cursor: pointer; | ||
32 | + } | ||
33 | +} | ||
34 | + | ||
35 | +.md-panel { | ||
36 | + &.tb-dashboard-select-panel { | ||
37 | + position: absolute; | ||
20 | } | 38 | } |
21 | } | 39 | } |
40 | + | ||
41 | +.tb-dashboard-select-panel { | ||
42 | + max-height: 150px; | ||
43 | + @media (min-height: 350px) { | ||
44 | + max-height: 250px; | ||
45 | + } | ||
46 | + max-width: 320px; | ||
47 | + @media (min-width: $layout-breakpoint-xs) { | ||
48 | + max-width: 100%; | ||
49 | + } | ||
50 | + min-width: 300px; | ||
51 | + background: white; | ||
52 | + border-radius: 4px; | ||
53 | + box-shadow: 0 7px 8px -4px rgba(0, 0, 0, 0.2), | ||
54 | + 0 13px 19px 2px rgba(0, 0, 0, 0.14), | ||
55 | + 0 5px 24px 4px rgba(0, 0, 0, 0.12); | ||
56 | + overflow-x: hidden; | ||
57 | + overflow-y: auto; | ||
58 | + md-content { | ||
59 | + background-color: #fff; | ||
60 | + } | ||
61 | +} |
@@ -16,7 +16,8 @@ | @@ -16,7 +16,8 @@ | ||
16 | 16 | ||
17 | --> | 17 | --> |
18 | 18 | ||
19 | -<md-select ng-required="tbRequired" | 19 | +<md-select hide-xs hide-sm hide-md |
20 | + ng-required="tbRequired" | ||
20 | ng-disabled="disabled" | 21 | ng-disabled="disabled" |
21 | ng-model="dashboardId" | 22 | ng-model="dashboardId" |
22 | aria-label="{{ 'dashboard.dashboard' | translate }}"> | 23 | aria-label="{{ 'dashboard.dashboard' | translate }}"> |
@@ -24,3 +25,11 @@ | @@ -24,3 +25,11 @@ | ||
24 | {{dashboard.title}} | 25 | {{dashboard.title}} |
25 | </md-option> | 26 | </md-option> |
26 | </md-select> | 27 | </md-select> |
28 | +<section hide-gt-md class="tb-dashboard-select"> | ||
29 | + <md-button class="md-icon-button" aria-label="{{ 'dashboard.select-dashboard' | translate }}" ng-click="openDashboardSelectPanel($event)"> | ||
30 | + <md-tooltip md-direction="{{tooltipDirection}}"> | ||
31 | + {{ 'dashboard.select-dashboard' | translate }} | ||
32 | + </md-tooltip> | ||
33 | + <md-icon aria-label="{{ 'dashboard.select-dashboard' | translate }}" class="material-icons">dashboards</md-icon> | ||
34 | + </md-button> | ||
35 | +</section> |
@@ -31,12 +31,12 @@ | @@ -31,12 +31,12 @@ | ||
31 | } | 31 | } |
32 | 32 | ||
33 | tb-datasource-entity { | 33 | tb-datasource-entity { |
34 | - @media (min-width: $layout-breakpoint-gt-sm) { | 34 | + @media (min-width: $layout-breakpoint-sm) { |
35 | padding-left: 4px; | 35 | padding-left: 4px; |
36 | padding-right: 4px; | 36 | padding-right: 4px; |
37 | } | 37 | } |
38 | tb-entity-alias-select { | 38 | tb-entity-alias-select { |
39 | - @media (min-width: $layout-breakpoint-gt-sm) { | 39 | + @media (min-width: $layout-breakpoint-sm) { |
40 | width: 200px; | 40 | width: 200px; |
41 | max-width: 200px; | 41 | max-width: 200px; |
42 | } | 42 | } |
@@ -16,7 +16,7 @@ | @@ -16,7 +16,7 @@ | ||
16 | @import '../../scss/constants'; | 16 | @import '../../scss/constants'; |
17 | 17 | ||
18 | .tb-datasource-func { | 18 | .tb-datasource-func { |
19 | - @media (min-width: $layout-breakpoint-gt-sm) { | 19 | + @media (min-width: $layout-breakpoint-sm) { |
20 | padding-left: 8px; | 20 | padding-left: 8px; |
21 | } | 21 | } |
22 | 22 |
@@ -45,10 +45,10 @@ md-sidenav.tb-sidenav-details { | @@ -45,10 +45,10 @@ md-sidenav.tb-sidenav-details { | ||
45 | width: 100% !important; | 45 | width: 100% !important; |
46 | max-width: 100% !important; | 46 | max-width: 100% !important; |
47 | z-index: 59 !important; | 47 | z-index: 59 !important; |
48 | - @media (min-width: $layout-breakpoint-gt-sm) { | 48 | + @media (min-width: $layout-breakpoint-sm) { |
49 | width: 80% !important; | 49 | width: 80% !important; |
50 | } | 50 | } |
51 | - @media (min-width: $layout-breakpoint-gt-md) { | 51 | + @media (min-width: $layout-breakpoint-md) { |
52 | width: 65% !important; | 52 | width: 65% !important; |
53 | } | 53 | } |
54 | @media (min-width: $layout-breakpoint-lg) { | 54 | @media (min-width: $layout-breakpoint-lg) { |
@@ -69,7 +69,7 @@ function Timewindow($compile, $templateCache, $filter, $mdPanel, $document, $mdM | @@ -69,7 +69,7 @@ function Timewindow($compile, $templateCache, $filter, $mdPanel, $document, $mdM | ||
69 | scope.isToolbar = angular.isDefined(attrs.isToolbar); | 69 | scope.isToolbar = angular.isDefined(attrs.isToolbar); |
70 | 70 | ||
71 | scope.hideLabel = function() { | 71 | scope.hideLabel = function() { |
72 | - return scope.isToolbar && !$mdMedia('gt-sm'); | 72 | + return scope.isToolbar && !$mdMedia('gt-md'); |
73 | } | 73 | } |
74 | 74 | ||
75 | var translationPending = false; | 75 | var translationPending = false; |
@@ -59,8 +59,16 @@ | @@ -59,8 +59,16 @@ | ||
59 | } | 59 | } |
60 | 60 | ||
61 | tb-timewindow { | 61 | tb-timewindow { |
62 | - span { | ||
63 | - pointer-events: all; | ||
64 | - cursor: pointer; | 62 | + min-width: 52px; |
63 | + section.tb-timewindow { | ||
64 | + min-height: 32px; | ||
65 | + padding: 0 6px; | ||
66 | + span { | ||
67 | + pointer-events: all; | ||
68 | + cursor: pointer; | ||
69 | + overflow: hidden; | ||
70 | + text-overflow: ellipsis; | ||
71 | + white-space: nowrap; | ||
72 | + } | ||
65 | } | 73 | } |
66 | } | 74 | } |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | limitations under the License. | 15 | limitations under the License. |
16 | 16 | ||
17 | --> | 17 | --> |
18 | -<section layout='row' layout-align="start center" ng-style="{minHeight: '32px', padding: '0 6px'}"> | 18 | +<section class="tb-timewindow" layout='row' layout-align="start center"> |
19 | <md-button ng-if="direction === 'left'" ng-disabled="disabled" class="md-icon-button tb-md-32" aria-label="{{ 'timewindow.edit' | translate }}" ng-click="openEditMode($event)"> | 19 | <md-button ng-if="direction === 'left'" ng-disabled="disabled" class="md-icon-button tb-md-32" aria-label="{{ 'timewindow.edit' | translate }}" ng-click="openEditMode($event)"> |
20 | <md-tooltip md-direction="{{tooltipDirection}}"> | 20 | <md-tooltip md-direction="{{tooltipDirection}}"> |
21 | {{ 'timewindow.edit' | translate }} | 21 | {{ 'timewindow.edit' | translate }} |
@@ -33,5 +33,5 @@ | @@ -33,5 +33,5 @@ | ||
33 | {{ 'timewindow.edit' | translate }} | 33 | {{ 'timewindow.edit' | translate }} |
34 | </md-tooltip> | 34 | </md-tooltip> |
35 | <ng-md-icon aria-label="{{ 'timewindow.date-range' | translate }}" icon="query_builder"></ng-md-icon> | 35 | <ng-md-icon aria-label="{{ 'timewindow.date-range' | translate }}" icon="query_builder"></ng-md-icon> |
36 | - </md-button> | 36 | + </md-button> |
37 | </section> | 37 | </section> |
@@ -65,7 +65,7 @@ | @@ -65,7 +65,7 @@ | ||
65 | <v-pane-header> | 65 | <v-pane-header> |
66 | <div layout="column"> | 66 | <div layout="column"> |
67 | <div>{{ 'widget-config.datasources' | translate }}</div> | 67 | <div>{{ 'widget-config.datasources' | translate }}</div> |
68 | - <div class="md-caption" style="color: rgba(0,0,0,0.57);" ng-if="typeParameters.maxDatasources != -1" | 68 | + <div class="md-caption" style="color: rgba(0,0,0,0.57);" ng-if="typeParameters.maxDatasources > -1" |
69 | translate="widget-config.maximum-datasources" | 69 | translate="widget-config.maximum-datasources" |
70 | translate-values="{count: typeParameters.maxDatasources}" | 70 | translate-values="{count: typeParameters.maxDatasources}" |
71 | translate-interpolation="messageformat" | 71 | translate-interpolation="messageformat" |
@@ -17,6 +17,12 @@ | @@ -17,6 +17,12 @@ | ||
17 | @import "~compass-sass-mixins/lib/compass"; | 17 | @import "~compass-sass-mixins/lib/compass"; |
18 | @import '../../scss/constants'; | 18 | @import '../../scss/constants'; |
19 | 19 | ||
20 | +$toolbar-height: 50px; | ||
21 | +$fullscreen-toolbar-height: 64px; | ||
22 | +$mobile-toolbar-height: 80px; | ||
23 | +$half-mobile-toolbar-height: 40px; | ||
24 | +$mobile-toolbar-height-total: 84px; | ||
25 | + | ||
20 | tb-dashboard-toolbar { | 26 | tb-dashboard-toolbar { |
21 | md-fab-toolbar { | 27 | md-fab-toolbar { |
22 | &.md-is-open { | 28 | &.md-is-open { |
@@ -68,42 +74,84 @@ tb-dashboard-toolbar { | @@ -68,42 +74,84 @@ tb-dashboard-toolbar { | ||
68 | } | 74 | } |
69 | } | 75 | } |
70 | .md-fab-toolbar-wrapper { | 76 | .md-fab-toolbar-wrapper { |
71 | - height: 64px; | 77 | + height: $mobile-toolbar-height-total; |
78 | + @media (min-width: $layout-breakpoint-sm) { | ||
79 | + height: $fullscreen-toolbar-height; | ||
80 | + } | ||
72 | md-toolbar { | 81 | md-toolbar { |
73 | - min-height: 64px; | ||
74 | - height: 64px; | 82 | + min-height: $mobile-toolbar-height; |
83 | + height: $mobile-toolbar-height; | ||
84 | + @media (min-width: $layout-breakpoint-sm) { | ||
85 | + min-height: $fullscreen-toolbar-height; | ||
86 | + height: $fullscreen-toolbar-height; | ||
87 | + } | ||
75 | } | 88 | } |
76 | } | 89 | } |
77 | } | 90 | } |
78 | .md-fab-toolbar-wrapper { | 91 | .md-fab-toolbar-wrapper { |
79 | - height: 50px; | 92 | + height: $mobile-toolbar-height-total; |
93 | + @media (min-width: $layout-breakpoint-sm) { | ||
94 | + height: $toolbar-height; | ||
95 | + } | ||
80 | md-toolbar { | 96 | md-toolbar { |
81 | - min-height: 50px; | ||
82 | - height: 50px; | 97 | + min-height: $mobile-toolbar-height; |
98 | + height: $mobile-toolbar-height; | ||
99 | + @media (min-width: $layout-breakpoint-sm) { | ||
100 | + min-height: $toolbar-height; | ||
101 | + height: $toolbar-height; | ||
102 | + } | ||
83 | md-fab-actions { | 103 | md-fab-actions { |
84 | font-size: 16px; | 104 | font-size: 16px; |
85 | margin-top: 0px; | 105 | margin-top: 0px; |
106 | + @media (max-width: $layout-breakpoint-sm) { | ||
107 | + height: $mobile-toolbar-height; | ||
108 | + max-height: $mobile-toolbar-height; | ||
109 | + } | ||
86 | .close-action { | 110 | .close-action { |
87 | margin-right: -18px; | 111 | margin-right: -18px; |
88 | } | 112 | } |
89 | .md-fab-action-item { | 113 | .md-fab-action-item { |
90 | width: 100%; | 114 | width: 100%; |
91 | - height: 46px; | ||
92 | - .tb-dashboard-action-panels { | 115 | + height: $mobile-toolbar-height; |
116 | + @media (min-width: $layout-breakpoint-sm) { | ||
93 | height: 46px; | 117 | height: 46px; |
94 | - flex-direction: row-reverse; | ||
95 | - .tb-dashboard-action-panel { | 118 | + } |
119 | + .tb-dashboard-action-panels { | ||
120 | + height: $mobile-toolbar-height; | ||
121 | + @media (min-width: $layout-breakpoint-sm) { | ||
96 | height: 46px; | 122 | height: 46px; |
123 | + } | ||
124 | + flex-direction: column-reverse; | ||
125 | + @media (min-width: $layout-breakpoint-sm) { | ||
97 | flex-direction: row-reverse; | 126 | flex-direction: row-reverse; |
98 | - div { | 127 | + } |
128 | + .tb-dashboard-action-panel { | ||
129 | + min-width: 0px; | ||
130 | + height: $half-mobile-toolbar-height; | ||
131 | + @media (min-width: $layout-breakpoint-sm) { | ||
99 | height: 46px; | 132 | height: 46px; |
100 | } | 133 | } |
134 | + flex-direction: row-reverse; | ||
135 | + div { | ||
136 | + height: $half-mobile-toolbar-height; | ||
137 | + @media (min-width: $layout-breakpoint-sm) { | ||
138 | + height: 46px; | ||
139 | + } | ||
140 | + } | ||
101 | md-select { | 141 | md-select { |
102 | pointer-events: all; | 142 | pointer-events: all; |
103 | } | 143 | } |
104 | tb-states-component { | 144 | tb-states-component { |
105 | pointer-events: all; | 145 | pointer-events: all; |
106 | } | 146 | } |
147 | + button.md-icon-button { | ||
148 | + min-width: 40px; | ||
149 | + @media (max-width: $layout-breakpoint-sm) { | ||
150 | + min-width: 28px; | ||
151 | + margin: 0px; | ||
152 | + padding: 2px; | ||
153 | + } | ||
154 | + } | ||
107 | } | 155 | } |
108 | } | 156 | } |
109 | } | 157 | } |
@@ -17,6 +17,10 @@ | @@ -17,6 +17,10 @@ | ||
17 | @import "~compass-sass-mixins/lib/compass"; | 17 | @import "~compass-sass-mixins/lib/compass"; |
18 | @import '../../scss/constants'; | 18 | @import '../../scss/constants'; |
19 | 19 | ||
20 | +$toolbar-height: 50px; | ||
21 | +$fullscreen-toolbar-height: 64px; | ||
22 | +$mobile-toolbar-height: 84px; | ||
23 | + | ||
20 | section.tb-dashboard-title { | 24 | section.tb-dashboard-title { |
21 | position: absolute; | 25 | position: absolute; |
22 | top: 0; | 26 | top: 0; |
@@ -44,10 +48,10 @@ div.tb-shrinked { | @@ -44,10 +48,10 @@ div.tb-shrinked { | ||
44 | 48 | ||
45 | tb-details-sidenav.tb-widget-details-sidenav { | 49 | tb-details-sidenav.tb-widget-details-sidenav { |
46 | md-sidenav.tb-sidenav-details { | 50 | md-sidenav.tb-sidenav-details { |
47 | - @media (min-width: $layout-breakpoint-gt-sm) { | 51 | + @media (min-width: $layout-breakpoint-sm) { |
48 | width: 85% !important; | 52 | width: 85% !important; |
49 | } | 53 | } |
50 | - @media (min-width: $layout-breakpoint-gt-md) { | 54 | + @media (min-width: $layout-breakpoint-md) { |
51 | width: 75% !important; | 55 | width: 75% !important; |
52 | } | 56 | } |
53 | @media (min-width: $layout-breakpoint-lg) { | 57 | @media (min-width: $layout-breakpoint-lg) { |
@@ -64,7 +68,7 @@ section.tb-dashboard-toolbar { | @@ -64,7 +68,7 @@ section.tb-dashboard-toolbar { | ||
64 | position: absolute; | 68 | position: absolute; |
65 | top: 0px; | 69 | top: 0px; |
66 | left: 0px; | 70 | left: 0px; |
67 | - z-index: 3; | 71 | + z-index: 13; |
68 | pointer-events: none; | 72 | pointer-events: none; |
69 | &.tb-dashboard-toolbar-opened { | 73 | &.tb-dashboard-toolbar-opened { |
70 | right: 0px; | 74 | right: 0px; |
@@ -79,10 +83,16 @@ section.tb-dashboard-toolbar { | @@ -79,10 +83,16 @@ section.tb-dashboard-toolbar { | ||
79 | .tb-dashboard-container { | 83 | .tb-dashboard-container { |
80 | &.tb-dashboard-toolbar-opened { | 84 | &.tb-dashboard-toolbar-opened { |
81 | &.is-fullscreen { | 85 | &.is-fullscreen { |
82 | - margin-top: 64px; | 86 | + margin-top: $mobile-toolbar-height; |
87 | + @media (min-width: $layout-breakpoint-sm) { | ||
88 | + margin-top: $fullscreen-toolbar-height; | ||
89 | + } | ||
83 | } | 90 | } |
84 | &:not(.is-fullscreen) { | 91 | &:not(.is-fullscreen) { |
85 | - margin-top: 50px; | 92 | + margin-top: $mobile-toolbar-height; |
93 | + @media (min-width: $layout-breakpoint-sm) { | ||
94 | + margin-top: $toolbar-height; | ||
95 | + } | ||
86 | @include transition(margin-top .3s cubic-bezier(.55,0,.55,.2)); | 96 | @include transition(margin-top .3s cubic-bezier(.55,0,.55,.2)); |
87 | } | 97 | } |
88 | } | 98 | } |
@@ -21,14 +21,16 @@ | @@ -21,14 +21,16 @@ | ||
21 | ng-class="{ 'tb-dashboard-toolbar-opened': vm.toolbarOpened, 'tb-dashboard-toolbar-closed': !vm.toolbarOpened }"> | 21 | ng-class="{ 'tb-dashboard-toolbar-opened': vm.toolbarOpened, 'tb-dashboard-toolbar-closed': !vm.toolbarOpened }"> |
22 | <tb-dashboard-toolbar ng-show="!vm.widgetEditMode" force-fullscreen="forceFullscreen" | 22 | <tb-dashboard-toolbar ng-show="!vm.widgetEditMode" force-fullscreen="forceFullscreen" |
23 | toolbar-opened="vm.toolbarOpened" on-trigger-click="vm.openToolbar()"> | 23 | toolbar-opened="vm.toolbarOpened" on-trigger-click="vm.openToolbar()"> |
24 | - <div class="tb-dashboard-action-panels" flex layout="row" layout-align="start center"> | ||
25 | - <div class="tb-dashboard-action-panel" flex="50" layout="row" layout-align="start center"> | 24 | + <div class="tb-dashboard-action-panels" layout-gt-sm="row" layout-align-gt-sm="space-between center" layout="column" layout-align="center stretch"> |
25 | + <div class="tb-dashboard-action-panel" flex-md="30" layout="row" layout-align-gt-sm="start center" layout-align="space-between center"> | ||
26 | <md-button ng-show="vm.showCloseToolbar()" aria-label="close-toolbar" class="md-icon-button close-action" ng-click="vm.closeToolbar()"> | 26 | <md-button ng-show="vm.showCloseToolbar()" aria-label="close-toolbar" class="md-icon-button close-action" ng-click="vm.closeToolbar()"> |
27 | <md-tooltip md-direction="bottom"> | 27 | <md-tooltip md-direction="bottom"> |
28 | {{ 'dashboard.close-toolbar' | translate }} | 28 | {{ 'dashboard.close-toolbar' | translate }} |
29 | </md-tooltip> | 29 | </md-tooltip> |
30 | <md-icon aria-label="close-toolbar" class="material-icons">arrow_forward</md-icon> | 30 | <md-icon aria-label="close-toolbar" class="material-icons">arrow_forward</md-icon> |
31 | </md-button> | 31 | </md-button> |
32 | + <tb-user-menu ng-if="!vm.isPublicUser() && forceFullscreen" hide-xs hide-sm display-user-info="true"> | ||
33 | + </tb-user-menu> | ||
32 | <md-button ng-show="vm.showRightLayoutSwitch()" aria-label="switch-layouts" class="md-icon-button" ng-click="vm.toggleLayouts()"> | 34 | <md-button ng-show="vm.showRightLayoutSwitch()" aria-label="switch-layouts" class="md-icon-button" ng-click="vm.toggleLayouts()"> |
33 | <ng-md-icon icon="{{vm.isRightLayoutOpened ? 'arrow_back' : 'menu'}}" options='{"easing": "circ-in-out", "duration": 375, "rotation": "none"}'></ng-md-icon> | 35 | <ng-md-icon icon="{{vm.isRightLayoutOpened ? 'arrow_back' : 'menu'}}" options='{"easing": "circ-in-out", "duration": 375, "rotation": "none"}'></ng-md-icon> |
34 | <md-tooltip md-direction="bottom"> | 36 | <md-tooltip md-direction="bottom"> |
@@ -39,8 +41,6 @@ | @@ -39,8 +41,6 @@ | ||
39 | aria-label="{{ 'fullscreen.fullscreen' | translate }}" | 41 | aria-label="{{ 'fullscreen.fullscreen' | translate }}" |
40 | class="md-icon-button"> | 42 | class="md-icon-button"> |
41 | </md-button> | 43 | </md-button> |
42 | - <tb-user-menu ng-if="!vm.isPublicUser() && forceFullscreen" display-user-info="true"> | ||
43 | - </tb-user-menu> | ||
44 | <md-button ng-show="vm.isEdit || vm.displayExport()" | 44 | <md-button ng-show="vm.isEdit || vm.displayExport()" |
45 | aria-label="{{ 'action.export' | translate }}" class="md-icon-button" | 45 | aria-label="{{ 'action.export' | translate }}" class="md-icon-button" |
46 | ng-click="vm.exportDashboard($event)"> | 46 | ng-click="vm.exportDashboard($event)"> |
@@ -79,8 +79,10 @@ | @@ -79,8 +79,10 @@ | ||
79 | customer-id="vm.currentCustomerId"> | 79 | customer-id="vm.currentCustomerId"> |
80 | </tb-dashboard-select> | 80 | </tb-dashboard-select> |
81 | </div> | 81 | </div> |
82 | - <div class="tb-dashboard-action-panel" flex="50" layout="row" layout-align="end center"> | ||
83 | - <div layout="row" layout-align="start center" ng-show="vm.isEdit"> | 82 | + <div class="tb-dashboard-action-panel" flex-md="70" layout="row" layout-align-gt-sm="end center" layout-align="space-between center"> |
83 | + <tb-user-menu ng-if="!vm.isPublicUser() && forceFullscreen" hide-gt-sm display-user-info="true"> | ||
84 | + </tb-user-menu> | ||
85 | + <div flex-xs flex-sm layout="row" layout-align-gt-sm="start center" layout-align="space-between center" ng-show="vm.isEdit"> | ||
84 | <md-button aria-label="{{ 'dashboard.manage-states' | translate }}" class="md-icon-button" | 86 | <md-button aria-label="{{ 'dashboard.manage-states' | translate }}" class="md-icon-button" |
85 | ng-click="vm.manageDashboardStates($event)"> | 87 | ng-click="vm.manageDashboardStates($event)"> |
86 | <md-tooltip md-direction="bottom"> | 88 | <md-tooltip md-direction="bottom"> |
@@ -96,14 +98,12 @@ | @@ -96,14 +98,12 @@ | ||
96 | <md-icon aria-label="{{ 'layout.manage' | translate }}" class="material-icons">view_compact</md-icon> | 98 | <md-icon aria-label="{{ 'layout.manage' | translate }}" class="material-icons">view_compact</md-icon> |
97 | </md-button> | 99 | </md-button> |
98 | </div> | 100 | </div> |
99 | - <div layout="row" layout-align="start center"> | ||
100 | - <tb-states-component ng-if="vm.isEdit" states-controller-id="'default'" | ||
101 | - dashboard-ctrl="vm" states="vm.dashboardConfiguration.states"> | ||
102 | - </tb-states-component> | ||
103 | - <tb-states-component ng-if="!vm.isEdit" states-controller-id="vm.dashboardConfiguration.settings.stateControllerId" | ||
104 | - dashboard-ctrl="vm" states="vm.dashboardConfiguration.states"> | ||
105 | - </tb-states-component> | ||
106 | - </div> | 101 | + <tb-states-component flex-xs flex-sm ng-if="vm.isEdit" states-controller-id="'default'" |
102 | + dashboard-ctrl="vm" states="vm.dashboardConfiguration.states"> | ||
103 | + </tb-states-component> | ||
104 | + <tb-states-component flex-xs flex-sm ng-if="!vm.isEdit" states-controller-id="vm.dashboardConfiguration.settings.stateControllerId" | ||
105 | + dashboard-ctrl="vm" states="vm.dashboardConfiguration.states"> | ||
106 | + </tb-states-component> | ||
107 | </div> | 107 | </div> |
108 | </div> | 108 | </div> |
109 | </tb-dashboard-toolbar> | 109 | </tb-dashboard-toolbar> |
@@ -146,7 +146,7 @@ | @@ -146,7 +146,7 @@ | ||
146 | ng-style="{minWidth: vm.rightLayoutWidth(), | 146 | ng-style="{minWidth: vm.rightLayoutWidth(), |
147 | maxWidth: vm.rightLayoutWidth(), | 147 | maxWidth: vm.rightLayoutWidth(), |
148 | height: vm.rightLayoutHeight(), | 148 | height: vm.rightLayoutHeight(), |
149 | - zIndex: 1}" | 149 | + zIndex: 12}" |
150 | md-component-id="right-dashboard-layout" | 150 | md-component-id="right-dashboard-layout" |
151 | aria-label="Right dashboard layout" | 151 | aria-label="Right dashboard layout" |
152 | md-is-open="vm.rightLayoutOpened" | 152 | md-is-open="vm.rightLayoutOpened" |
@@ -14,6 +14,8 @@ | @@ -14,6 +14,8 @@ | ||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | +import './default-state-controller.scss'; | ||
18 | + | ||
17 | /*@ngInject*/ | 19 | /*@ngInject*/ |
18 | export default function DefaultStateController($scope, $timeout, $location, $state, | 20 | export default function DefaultStateController($scope, $timeout, $location, $state, |
19 | $stateParams, utils, types, dashboardUtils, preservedState) { | 21 | $stateParams, utils, types, dashboardUtils, preservedState) { |
1 | +/** | ||
2 | + * Copyright © 2016-2017 The Thingsboard Authors | ||
3 | + * | ||
4 | + * Licensed under the Apache License, Version 2.0 (the "License"); | ||
5 | + * you may not use this file except in compliance with the License. | ||
6 | + * You may obtain a copy of the License at | ||
7 | + * | ||
8 | + * http://www.apache.org/licenses/LICENSE-2.0 | ||
9 | + * | ||
10 | + * Unless required by applicable law or agreed to in writing, software | ||
11 | + * distributed under the License is distributed on an "AS IS" BASIS, | ||
12 | + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
13 | + * See the License for the specific language governing permissions and | ||
14 | + * limitations under the License. | ||
15 | + */ | ||
16 | + | ||
17 | +md-select.default-state-controller { | ||
18 | + margin: 0px; | ||
19 | +} |
@@ -15,7 +15,7 @@ | @@ -15,7 +15,7 @@ | ||
15 | limitations under the License. | 15 | limitations under the License. |
16 | 16 | ||
17 | --> | 17 | --> |
18 | -<md-select ng-show="vm.displayStateSelection()" aria-label="{{ 'dashboard.state' | translate }}" ng-model="vm.stateObject[0].id"> | 18 | +<md-select class="default-state-controller" ng-show="vm.displayStateSelection()" aria-label="{{ 'dashboard.state' | translate }}" ng-model="vm.stateObject[0].id"> |
19 | <md-option ng-repeat="(stateId, state) in vm.states" ng-value="stateId"> | 19 | <md-option ng-repeat="(stateId, state) in vm.states" ng-value="stateId"> |
20 | {{vm.getStateName(stateId, state)}} | 20 | {{vm.getStateName(stateId, state)}} |
21 | </md-option> | 21 | </md-option> |
@@ -14,19 +14,33 @@ | @@ -14,19 +14,33 @@ | ||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | +@import '../../../scss/constants'; | ||
18 | + | ||
19 | +tb-states-component { | ||
20 | + min-width: 0px; | ||
21 | +} | ||
22 | + | ||
17 | .entity-state-controller { | 23 | .entity-state-controller { |
18 | .state-divider { | 24 | .state-divider { |
19 | - font-size: 28px; | 25 | + font-size: 18px; |
20 | padding-left: 15px; | 26 | padding-left: 15px; |
21 | padding-right: 15px; | 27 | padding-right: 15px; |
28 | + overflow: hidden; | ||
29 | + text-overflow: ellipsis; | ||
30 | + white-space: nowrap; | ||
31 | + pointer-events: none; | ||
22 | } | 32 | } |
23 | .state-entry { | 33 | .state-entry { |
24 | - font-size: 22px; | 34 | + font-size: 18px; |
35 | + overflow: hidden; | ||
36 | + text-overflow: ellipsis; | ||
37 | + white-space: nowrap; | ||
25 | outline: none; | 38 | outline: none; |
26 | } | 39 | } |
27 | md-select { | 40 | md-select { |
41 | + margin: 0px; | ||
28 | .md-text { | 42 | .md-text { |
29 | - font-size: 22px; | 43 | + font-size: 18px; |
30 | font-weight: bold; | 44 | font-weight: bold; |
31 | } | 45 | } |
32 | } | 46 | } |
@@ -15,15 +15,13 @@ | @@ -15,15 +15,13 @@ | ||
15 | limitations under the License. | 15 | limitations under the License. |
16 | 16 | ||
17 | --> | 17 | --> |
18 | -<div class="entity-state-controller"> | 18 | +<div class="entity-state-controller" layout="row" layout-align="start center"> |
19 | <div ng-if="!vm.dashboardCtrl.isMobile || vm.stateObject.length===1" layout="row" layout-align="start center"> | 19 | <div ng-if="!vm.dashboardCtrl.isMobile || vm.stateObject.length===1" layout="row" layout-align="start center"> |
20 | - <div layout="row" layout-align="start center" ng-repeat="state in vm.stateObject track by $index"> | ||
21 | - <span class='state-divider' ng-if="$index"> > </span> | ||
22 | - <span class='state-entry' ng-style="{fontWeight: $last ? 'bold' : 'normal', | ||
23 | - cursor: $last ? 'default' : 'pointer'}" ng-click="vm.navigatePrevState($index)"> | ||
24 | - {{vm.getStateName($index)}} | ||
25 | - </span> | ||
26 | - </div> | 20 | + <span ng-repeat="state in vm.stateObject track by $index" class='state-entry' ng-style="{fontWeight: $last ? 'bold' : 'normal', |
21 | + cursor: $last ? 'default' : 'pointer'}" ng-click="vm.navigatePrevState($index)"> | ||
22 | + {{vm.getStateName($index)}} | ||
23 | + <span class='state-divider' ng-hide="$last"> > </span> | ||
24 | + </span> | ||
27 | </div> | 25 | </div> |
28 | <md-select ng-if="vm.dashboardCtrl.isMobile && vm.stateObject.length > 1" aria-label="{{ 'dashboard.state' | translate }}" ng-model="vm.selectedStateIndex"> | 26 | <md-select ng-if="vm.dashboardCtrl.isMobile && vm.stateObject.length > 1" aria-label="{{ 'dashboard.state' | translate }}" ng-model="vm.selectedStateIndex"> |
29 | <md-option ng-repeat="state in vm.stateObject track by $index" ng-value="$index"> | 27 | <md-option ng-repeat="state in vm.stateObject track by $index" ng-value="$index"> |
@@ -16,14 +16,14 @@ | @@ -16,14 +16,14 @@ | ||
16 | 16 | ||
17 | --> | 17 | --> |
18 | 18 | ||
19 | -<section class="tb-aliases-entity-select" layout='row' layout-align="start center" ng-style="{minHeight: '32px', padding: '0 6px'}"> | 19 | +<section class="tb-aliases-entity-select" layout='row' layout-align="start center"> |
20 | <md-button class="md-icon-button" aria-label="{{ 'entity.select-entities' | translate }}" ng-click="openEditMode($event)"> | 20 | <md-button class="md-icon-button" aria-label="{{ 'entity.select-entities' | translate }}" ng-click="openEditMode($event)"> |
21 | <md-tooltip md-direction="{{tooltipDirection}}"> | 21 | <md-tooltip md-direction="{{tooltipDirection}}"> |
22 | {{ 'entity.select-entities' | translate }} | 22 | {{ 'entity.select-entities' | translate }} |
23 | </md-tooltip> | 23 | </md-tooltip> |
24 | <md-icon aria-label="{{ 'entity.select-entities' | translate }}" class="material-icons">devices_other</md-icon> | 24 | <md-icon aria-label="{{ 'entity.select-entities' | translate }}" class="material-icons">devices_other</md-icon> |
25 | </md-button> | 25 | </md-button> |
26 | - <span hide-xs hide-sm ng-click="openEditMode($event)"> | 26 | + <span hide-xs hide-sm hide-md ng-click="openEditMode($event)"> |
27 | <md-tooltip md-direction="{{tooltipDirection}}"> | 27 | <md-tooltip md-direction="{{tooltipDirection}}"> |
28 | {{ 'entity.select-entities' | translate }} | 28 | {{ 'entity.select-entities' | translate }} |
29 | </md-tooltip> | 29 | </md-tooltip> |
@@ -14,6 +14,12 @@ | @@ -14,6 +14,12 @@ | ||
14 | * limitations under the License. | 14 | * limitations under the License. |
15 | */ | 15 | */ |
16 | 16 | ||
17 | +@import '../../../scss/constants'; | ||
18 | + | ||
19 | +tb-aliases-entity-select { | ||
20 | + min-width: 52px; | ||
21 | +} | ||
22 | + | ||
17 | .md-panel { | 23 | .md-panel { |
18 | &.tb-aliases-entity-select-panel { | 24 | &.tb-aliases-entity-select-panel { |
19 | position: absolute; | 25 | position: absolute; |
@@ -38,9 +44,18 @@ | @@ -38,9 +44,18 @@ | ||
38 | } | 44 | } |
39 | } | 45 | } |
40 | 46 | ||
41 | -.tb-aliases-entity-select { | 47 | +section.tb-aliases-entity-select { |
48 | + min-height: 32px; | ||
49 | + padding: 0 6px; | ||
50 | + @media (max-width: $layout-breakpoint-sm) { | ||
51 | + padding: 0px; | ||
52 | + } | ||
42 | span { | 53 | span { |
54 | + max-width: 200px; | ||
43 | pointer-events: all; | 55 | pointer-events: all; |
44 | cursor: pointer; | 56 | cursor: pointer; |
57 | + overflow: hidden; | ||
58 | + text-overflow: ellipsis; | ||
59 | + white-space: nowrap; | ||
45 | } | 60 | } |
46 | } | 61 | } |
@@ -16,7 +16,7 @@ | @@ -16,7 +16,7 @@ | ||
16 | 16 | ||
17 | --> | 17 | --> |
18 | <section layout="row"> | 18 | <section layout="row"> |
19 | - <div hide-xs hide-sm ng-show="vm.displayUserInfo" class="tb-user-info" layout="row"> | 19 | + <div hide-xs hide-sm hide-md ng-show="vm.displayUserInfo" class="tb-user-info" layout="row"> |
20 | <md-icon aria-label="{{ 'home.avatar' | translate }}" class="material-icons tb-mini-avatar">account_circle</md-icon> | 20 | <md-icon aria-label="{{ 'home.avatar' | translate }}" class="material-icons tb-mini-avatar">account_circle</md-icon> |
21 | <div layout="column"> | 21 | <div layout="column"> |
22 | <span class="tb-user-display-name">{{vm.userDisplayName()}}</span> | 22 | <span class="tb-user-display-name">{{vm.userDisplayName()}}</span> |
@@ -21,10 +21,10 @@ | @@ -21,10 +21,10 @@ | ||
21 | padding-bottom: 8px; | 21 | padding-bottom: 8px; |
22 | } | 22 | } |
23 | tb-dashboard-autocomplete { | 23 | tb-dashboard-autocomplete { |
24 | - @media (min-width: $layout-breakpoint-gt-sm) { | 24 | + @media (min-width: $layout-breakpoint-sm) { |
25 | padding-right: 12px; | 25 | padding-right: 12px; |
26 | } | 26 | } |
27 | - @media (max-width: $layout-breakpoint-gt-sm) { | 27 | + @media (max-width: $layout-breakpoint-sm) { |
28 | padding-bottom: 12px; | 28 | padding-bottom: 12px; |
29 | } | 29 | } |
30 | } | 30 | } |
@@ -37,9 +37,3 @@ $layout-breakpoint-sm: 960px !default; | @@ -37,9 +37,3 @@ $layout-breakpoint-sm: 960px !default; | ||
37 | $layout-breakpoint-md: 1280px !default; | 37 | $layout-breakpoint-md: 1280px !default; |
38 | $layout-breakpoint-xmd: 1600px !default; | 38 | $layout-breakpoint-xmd: 1600px !default; |
39 | $layout-breakpoint-lg: 1920px !default; | 39 | $layout-breakpoint-lg: 1920px !default; |
40 | - | ||
41 | -$layout-breakpoint-gt-xs: 601px !default; | ||
42 | -$layout-breakpoint-gt-sm: 961px !default; | ||
43 | -$layout-breakpoint-gt-md: 1281px !default; | ||
44 | -$layout-breakpoint-gt-xmd: 1601px !default; | ||
45 | -$layout-breakpoint-gt-lg: 1921px !default; |
@@ -549,7 +549,7 @@ section.tb-footer-buttons { | @@ -549,7 +549,7 @@ section.tb-footer-buttons { | ||
549 | position: fixed; | 549 | position: fixed; |
550 | right: 20px; | 550 | right: 20px; |
551 | bottom: 20px; | 551 | bottom: 20px; |
552 | - z-index: 2; | 552 | + z-index: 13; |
553 | pointer-events: none; | 553 | pointer-events: none; |
554 | } | 554 | } |
555 | 555 |