diff --git a/application/build.gradle b/application/build.gradle
index 1d8a526fd1..01761692f2 100644
--- a/application/build.gradle
+++ b/application/build.gradle
@@ -1,5 +1,5 @@
/**
- * Copyright © 2016-2017 The Thingsboard Authors
+ * 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.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
import org.apache.tools.ant.filters.ReplaceTokens
buildscript {
diff --git a/application/pom.xml b/application/pom.xml
index e5a4a4e614..8449246059 100644
--- a/application/pom.xml
+++ b/application/pom.xml
@@ -1,6 +1,6 @@
+
+
+
+
audit-log.audit-log-details
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ 'action.close' |
+ translate }}
+
+
+
diff --git a/ui/src/app/audit/audit-log-header.directive.js b/ui/src/app/audit/audit-log-header.directive.js
new file mode 100644
index 0000000000..3388cc273c
--- /dev/null
+++ b/ui/src/app/audit/audit-log-header.directive.js
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+/* eslint-disable import/no-unresolved, import/default */
+
+import auditLogHeaderTemplate from './audit-log-header.tpl.html';
+
+/* eslint-enable import/no-unresolved, import/default */
+
+/*@ngInject*/
+export default function AuditLogHeaderDirective($compile, $templateCache, types) {
+
+ var linker = function (scope, element, attrs) {
+
+ var template = $templateCache.get(auditLogHeaderTemplate);
+ element.html(template);
+ scope.auditLogMode = attrs.auditLogMode;
+ scope.types = types;
+ $compile(element.contents())(scope);
+
+ };
+
+ return {
+ restrict: "A",
+ replace: false,
+ link: linker,
+ scope: false
+ };
+}
diff --git a/ui/src/app/audit/audit-log-header.tpl.html b/ui/src/app/audit/audit-log-header.tpl.html
new file mode 100644
index 0000000000..741c832cb1
--- /dev/null
+++ b/ui/src/app/audit/audit-log-header.tpl.html
@@ -0,0 +1,24 @@
+
+audit-log.timestamp
+audit-log.entity-type
+audit-log.entity-name
+audit-log.user
+audit-log.type
+audit-log.status
+audit-log.details
diff --git a/ui/src/app/audit/audit-log-row.directive.js b/ui/src/app/audit/audit-log-row.directive.js
new file mode 100644
index 0000000000..2c2e170690
--- /dev/null
+++ b/ui/src/app/audit/audit-log-row.directive.js
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+/* eslint-disable import/no-unresolved, import/default */
+
+import auditLogDetailsDialogTemplate from './audit-log-details-dialog.tpl.html';
+
+import auditLogRowTemplate from './audit-log-row.tpl.html';
+
+/* eslint-enable import/no-unresolved, import/default */
+
+/*@ngInject*/
+export default function AuditLogRowDirective($compile, $templateCache, types, $mdDialog, $document) {
+
+ var linker = function (scope, element, attrs) {
+
+ var template = $templateCache.get(auditLogRowTemplate);
+ element.html(template);
+
+ scope.auditLog = attrs.auditLog;
+ scope.auditLogMode = attrs.auditLogMode;
+ scope.types = types;
+
+ scope.showAuditLogDetails = function($event) {
+ var onShowingCallback = {
+ onShowing: function(){}
+ }
+ $mdDialog.show({
+ controller: 'AuditLogDetailsDialogController',
+ controllerAs: 'vm',
+ templateUrl: auditLogDetailsDialogTemplate,
+ locals: {
+ auditLog: scope.auditLog,
+ showingCallback: onShowingCallback
+ },
+ parent: angular.element($document[0].body),
+ targetEvent: $event,
+ fullscreen: true,
+ skipHide: true,
+ onShowing: function(scope, element) {
+ onShowingCallback.onShowing(scope, element);
+ }
+ });
+ }
+
+ $compile(element.contents())(scope);
+ }
+
+ return {
+ restrict: "A",
+ replace: false,
+ link: linker,
+ scope: false
+ };
+}
diff --git a/ui/src/app/audit/audit-log-row.tpl.html b/ui/src/app/audit/audit-log-row.tpl.html
new file mode 100644
index 0000000000..a735169b1d
--- /dev/null
+++ b/ui/src/app/audit/audit-log-row.tpl.html
@@ -0,0 +1,36 @@
+
+{{ auditLog.createdTime | date : 'yyyy-MM-dd HH:mm:ss' }}
+{{ auditLog.entityTypeText }}
+{{ auditLog.entityName }}
+{{ auditLog.userName }}
+{{ auditLog.actionTypeText }}
+{{ auditLog.actionStatusText }}
+
+
+
+ {{ 'audit-log.details' | translate }}
+
+
+ more_horiz
+
+
+
diff --git a/ui/src/app/audit/audit-log-table.directive.js b/ui/src/app/audit/audit-log-table.directive.js
new file mode 100644
index 0000000000..81bfd4fe64
--- /dev/null
+++ b/ui/src/app/audit/audit-log-table.directive.js
@@ -0,0 +1,262 @@
+/*
+ * 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 './audit-log.scss';
+
+/* eslint-disable import/no-unresolved, import/default */
+
+import auditLogTableTemplate from './audit-log-table.tpl.html';
+
+/* eslint-enable import/no-unresolved, import/default */
+
+/*@ngInject*/
+export default function AuditLogTableDirective($compile, $templateCache, $rootScope, $filter, $translate, types, auditLogService) {
+
+ var linker = function (scope, element) {
+
+ var template = $templateCache.get(auditLogTableTemplate);
+
+ element.html(template);
+
+ scope.types = types;
+
+ var pageSize = 20;
+ var startTime = 0;
+ var endTime = 0;
+
+ scope.timewindow = {
+ history: {
+ timewindowMs: 24 * 60 * 60 * 1000 // 1 day
+ }
+ }
+
+ scope.topIndex = 0;
+ scope.searchText = '';
+
+ scope.theAuditLogs = {
+ getItemAtIndex: function (index) {
+ if (index > scope.auditLogs.filtered.length) {
+ scope.theAuditLogs.fetchMoreItems_(index);
+ return null;
+ }
+ return scope.auditLogs.filtered[index];
+ },
+
+ getLength: function () {
+ if (scope.auditLogs.hasNext) {
+ return scope.auditLogs.filtered.length + scope.auditLogs.nextPageLink.limit;
+ } else {
+ return scope.auditLogs.filtered.length;
+ }
+ },
+
+ fetchMoreItems_: function () {
+ if (scope.auditLogs.hasNext && !scope.auditLogs.pending) {
+ var promise = getAuditLogsPromise(scope.auditLogs.nextPageLink);
+ if (promise) {
+ scope.auditLogs.pending = true;
+ promise.then(
+ function success(auditLogs) {
+ scope.auditLogs.data = scope.auditLogs.data.concat(prepareAuditLogsData(auditLogs.data));
+ scope.auditLogs.filtered = $filter('filter')(scope.auditLogs.data, {$: scope.searchText});
+ scope.auditLogs.nextPageLink = auditLogs.nextPageLink;
+ scope.auditLogs.hasNext = auditLogs.hasNext;
+ if (scope.auditLogs.hasNext) {
+ scope.auditLogs.nextPageLink.limit = pageSize;
+ }
+ scope.auditLogs.pending = false;
+ },
+ function fail() {
+ scope.auditLogs.hasNext = false;
+ scope.auditLogs.pending = false;
+ });
+ } else {
+ scope.auditLogs.hasNext = false;
+ }
+ }
+ }
+ };
+
+ function prepareAuditLogsData(data) {
+ data.forEach(
+ auditLog => {
+ auditLog.entityTypeText = $translate.instant(types.entityTypeTranslations[auditLog.entityId.entityType].type);
+ auditLog.actionTypeText = $translate.instant(types.auditLogActionType[auditLog.actionType].name);
+ auditLog.actionStatusText = $translate.instant(types.auditLogActionStatus[auditLog.actionStatus].name);
+ auditLog.actionDataText = auditLog.actionData ? angular.toJson(auditLog.actionData, true) : '';
+ }
+ );
+ return data;
+ }
+
+ scope.$watch("entityId", function(newVal, prevVal) {
+ if (newVal && !angular.equals(newVal, prevVal)) {
+ resetFilter();
+ scope.reload();
+ }
+ });
+
+ scope.$watch("userId", function(newVal, prevVal) {
+ if (newVal && !angular.equals(newVal, prevVal)) {
+ resetFilter();
+ scope.reload();
+ }
+ });
+
+ scope.$watch("customerId", function(newVal, prevVal) {
+ if (newVal && !angular.equals(newVal, prevVal)) {
+ resetFilter();
+ scope.reload();
+ }
+ });
+
+ function getAuditLogsPromise(pageLink) {
+ switch(scope.auditLogMode) {
+ case types.auditLogMode.tenant:
+ return auditLogService.getAuditLogs(pageLink);
+ case types.auditLogMode.entity:
+ if (scope.entityType && scope.entityId) {
+ return auditLogService.getAuditLogsByEntityId(scope.entityType, scope.entityId,
+ pageLink);
+ } else {
+ return null;
+ }
+ case types.auditLogMode.user:
+ if (scope.userId) {
+ return auditLogService.getAuditLogsByUserId(scope.userId, pageLink);
+ } else {
+ return null;
+ }
+ case types.auditLogMode.customer:
+ if (scope.customerId) {
+ return auditLogService.getAuditLogsByCustomerId(scope.customerId, pageLink);
+ } else {
+ return null;
+ }
+ }
+ }
+
+ function destroyWatchers() {
+ if (scope.timewindowWatchHandle) {
+ scope.timewindowWatchHandle();
+ scope.timewindowWatchHandle = null;
+ }
+ if (scope.searchTextWatchHandle) {
+ scope.searchTextWatchHandle();
+ scope.searchTextWatchHandle = null;
+ }
+ }
+
+ function initWatchers() {
+ scope.timewindowWatchHandle = scope.$watch("timewindow", function(newVal, prevVal) {
+ if (newVal && !angular.equals(newVal, prevVal)) {
+ scope.reload();
+ }
+ }, true);
+
+ scope.searchTextWatchHandle = scope.$watch("searchText", function(newVal, prevVal) {
+ if (!angular.equals(newVal, prevVal)) {
+ scope.searchTextUpdated();
+ }
+ }, true);
+ }
+
+ function resetFilter() {
+ destroyWatchers();
+ scope.timewindow = {
+ history: {
+ timewindowMs: 24 * 60 * 60 * 1000 // 1 day
+ }
+ };
+ scope.searchText = '';
+ initWatchers();
+ }
+
+ function updateTimeWindowRange () {
+ if (scope.timewindow.history.timewindowMs) {
+ var currentTime = (new Date).getTime();
+ startTime = currentTime - scope.timewindow.history.timewindowMs;
+ endTime = currentTime;
+ } else {
+ startTime = scope.timewindow.history.fixedTimewindow.startTimeMs;
+ endTime = scope.timewindow.history.fixedTimewindow.endTimeMs;
+ }
+ }
+
+ scope.reload = function() {
+ scope.topIndex = 0;
+ updateTimeWindowRange();
+ scope.auditLogs = {
+ data: [],
+ filtered: [],
+ nextPageLink: {
+ limit: pageSize,
+ startTime: startTime,
+ endTime: endTime
+ },
+ hasNext: true,
+ pending: false
+ };
+ scope.theAuditLogs.getItemAtIndex(pageSize);
+ }
+
+ scope.searchTextUpdated = function() {
+ scope.auditLogs.filtered = $filter('filter')(scope.auditLogs.data, {$: scope.searchText});
+ scope.theAuditLogs.getItemAtIndex(pageSize);
+ }
+
+ scope.noData = function() {
+ return scope.auditLogs.data.length == 0 && !scope.auditLogs.hasNext;
+ }
+
+ scope.hasData = function() {
+ return scope.auditLogs.data.length > 0;
+ }
+
+ scope.loading = function() {
+ return $rootScope.loading;
+ }
+
+ scope.hasScroll = function() {
+ var repeatContainer = scope.repeatContainer[0];
+ if (repeatContainer) {
+ var scrollElement = repeatContainer.children[0];
+ if (scrollElement) {
+ return scrollElement.scrollHeight > scrollElement.clientHeight;
+ }
+ }
+ return false;
+ }
+
+ scope.reload();
+
+ initWatchers();
+
+ $compile(element.contents())(scope);
+ }
+
+ return {
+ restrict: "E",
+ link: linker,
+ scope: {
+ entityType: '=?',
+ entityId: '=?',
+ userId: '=?',
+ customerId: '=?',
+ auditLogMode: '@',
+ pageMode: '@?'
+ }
+ };
+}
diff --git a/ui/src/app/audit/audit-log-table.tpl.html b/ui/src/app/audit/audit-log-table.tpl.html
new file mode 100644
index 0000000000..46a4679429
--- /dev/null
+++ b/ui/src/app/audit/audit-log-table.tpl.html
@@ -0,0 +1,68 @@
+
+
+
+
+
+
+
+
+
+ audit-log.no-audit-logs-prompt
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ui/src/app/audit/audit-log.routes.js b/ui/src/app/audit/audit-log.routes.js
new file mode 100644
index 0000000000..bb098c79fa
--- /dev/null
+++ b/ui/src/app/audit/audit-log.routes.js
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+/* eslint-disable import/no-unresolved, import/default */
+
+import auditLogsTemplate from './audit-logs.tpl.html';
+
+/* eslint-enable import/no-unresolved, import/default */
+
+/*@ngInject*/
+export default function AuditLogRoutes($stateProvider) {
+ $stateProvider
+ .state('home.auditLogs', {
+ url: '/auditLogs',
+ module: 'private',
+ auth: ['TENANT_ADMIN'],
+ views: {
+ "content@home": {
+ templateUrl: auditLogsTemplate,
+ controller: 'AuditLogsController',
+ controllerAs: 'vm'
+ }
+ },
+ data: {
+ searchEnabled: false,
+ pageTitle: 'audit-log.audit-logs'
+ },
+ ncyBreadcrumb: {
+ label: '{"icon": "track_changes", "label": "audit-log.audit-logs"}'
+ }
+ });
+}
diff --git a/ui/src/app/audit/audit-log.scss b/ui/src/app/audit/audit-log.scss
new file mode 100644
index 0000000000..7cae1076a2
--- /dev/null
+++ b/ui/src/app/audit/audit-log.scss
@@ -0,0 +1,90 @@
+/**
+ * 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.
+ */
+.tb-audit-logs {
+ background-color: #fff;
+ .tb-audit-log-margin-18px {
+ margin-bottom: 18px;
+ }
+ .tb-audit-log-toolbar {
+ font-size: 20px;
+ }
+ md-input-container.tb-audit-log-search-input {
+ .md-errors-spacer {
+ min-height: 0px;
+ }
+ }
+}
+
+.tb-audit-log-container {
+ overflow-x: auto;
+}
+
+
+
+md-list.tb-audit-log-table {
+ padding: 0px;
+ min-width: 700px;
+ &.tb-audit-log-table-full {
+ min-width: 900px;
+ }
+
+ md-list-item {
+ padding: 0px;
+ }
+
+ .tb-row {
+ height: 48px;
+ padding: 0px;
+ overflow: hidden;
+ }
+
+ .tb-row:hover {
+ background-color: #EEEEEE;
+ }
+
+ .tb-header:hover {
+ background: none;
+ }
+
+ .tb-header {
+ .tb-cell {
+ color: rgba(0,0,0,.54);
+ font-size: 12px;
+ font-weight: 700;
+ white-space: nowrap;
+ background: none;
+ }
+ }
+
+ .tb-cell {
+ padding: 0 24px;
+ margin: auto 0;
+ color: rgba(0,0,0,.87);
+ font-size: 13px;
+ vertical-align: middle;
+ text-align: left;
+ overflow: hidden;
+ .md-button {
+ padding: 0;
+ margin: 0;
+ }
+ }
+
+ .tb-cell.tb-number {
+ text-align: right;
+ }
+
+}
diff --git a/ui/src/app/audit/audit-logs.controller.js b/ui/src/app/audit/audit-logs.controller.js
new file mode 100644
index 0000000000..25bca75e53
--- /dev/null
+++ b/ui/src/app/audit/audit-logs.controller.js
@@ -0,0 +1,23 @@
+/*
+ * 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.
+ */
+/*@ngInject*/
+export default function AuditLogsController(types) {
+
+ var vm = this;
+
+ vm.types = types;
+
+}
\ No newline at end of file
diff --git a/ui/src/app/audit/audit-logs.tpl.html b/ui/src/app/audit/audit-logs.tpl.html
new file mode 100644
index 0000000000..feea322f0b
--- /dev/null
+++ b/ui/src/app/audit/audit-logs.tpl.html
@@ -0,0 +1,22 @@
+
+
+
diff --git a/ui/src/app/audit/index.js b/ui/src/app/audit/index.js
new file mode 100644
index 0000000000..d522e09d4d
--- /dev/null
+++ b/ui/src/app/audit/index.js
@@ -0,0 +1,30 @@
+/*
+ * 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 AuditLogRoutes from './audit-log.routes';
+import AuditLogsController from './audit-logs.controller';
+import AuditLogDetailsDialogController from './audit-log-details-dialog.controller';
+import AuditLogHeaderDirective from './audit-log-header.directive';
+import AuditLogRowDirective from './audit-log-row.directive';
+import AuditLogTableDirective from './audit-log-table.directive';
+
+export default angular.module('thingsboard.auditLog', [])
+ .config(AuditLogRoutes)
+ .controller('AuditLogsController', AuditLogsController)
+ .controller('AuditLogDetailsDialogController', AuditLogDetailsDialogController)
+ .directive('tbAuditLogHeader', AuditLogHeaderDirective)
+ .directive('tbAuditLogRow', AuditLogRowDirective)
+ .directive('tbAuditLogTable', AuditLogTableDirective)
+ .name;
diff --git a/ui/src/app/common/dashboard-utils.service.js b/ui/src/app/common/dashboard-utils.service.js
index c4b2486b68..f1401b7903 100644
--- a/ui/src/app/common/dashboard-utils.service.js
+++ b/ui/src/app/common/dashboard-utils.service.js
@@ -1,5 +1,5 @@
/*
- * Copyright © 2016-2017 The Thingsboard Authors
+ * 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.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
export default angular.module('thingsboard.dashboardUtils', [])
.factory('dashboardUtils', DashboardUtils)
.name;
diff --git a/ui/src/app/common/raf.provider.js b/ui/src/app/common/raf.provider.js
index 136f6ae6f7..13ff62eb39 100644
--- a/ui/src/app/common/raf.provider.js
+++ b/ui/src/app/common/raf.provider.js
@@ -1,5 +1,5 @@
/*
- * Copyright © 2016-2017 The Thingsboard Authors
+ * 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.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
export default angular.module('thingsboard.raf', [])
.provider('tbRaf', TbRAFProvider)
.name;
diff --git a/ui/src/app/common/types.constant.js b/ui/src/app/common/types.constant.js
index 5b3c9e4ac4..ef6ffde28a 100644
--- a/ui/src/app/common/types.constant.js
+++ b/ui/src/app/common/types.constant.js
@@ -1,5 +1,5 @@
/*
- * Copyright © 2016-2017 The Thingsboard Authors
+ * 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.
@@ -156,6 +156,63 @@ export default angular.module('thingsboard.types', [])
color: "green"
}
},
+ auditLogActionType: {
+ "ADDED": {
+ name: "audit-log.type-added"
+ },
+ "DELETED": {
+ name: "audit-log.type-deleted"
+ },
+ "UPDATED": {
+ name: "audit-log.type-updated"
+ },
+ "ATTRIBUTES_UPDATED": {
+ name: "audit-log.type-attributes-updated"
+ },
+ "ATTRIBUTES_DELETED": {
+ name: "audit-log.type-attributes-deleted"
+ },
+ "RPC_CALL": {
+ name: "audit-log.type-rpc-call"
+ },
+ "CREDENTIALS_UPDATED": {
+ name: "audit-log.type-credentials-updated"
+ },
+ "ASSIGNED_TO_CUSTOMER": {
+ name: "audit-log.type-assigned-to-customer"
+ },
+ "UNASSIGNED_FROM_CUSTOMER": {
+ name: "audit-log.type-unassigned-from-customer"
+ },
+ "ACTIVATED": {
+ name: "audit-log.type-activated"
+ },
+ "SUSPENDED": {
+ name: "audit-log.type-suspended"
+ },
+ "CREDENTIALS_READ": {
+ name: "audit-log.type-credentials-read"
+ },
+ "ATTRIBUTES_READ": {
+ name: "audit-log.type-attributes-read"
+ }
+ },
+ auditLogActionStatus: {
+ "SUCCESS": {
+ value: "SUCCESS",
+ name: "audit-log.status-success"
+ },
+ "FAILURE": {
+ value: "FAILURE",
+ name: "audit-log.status-failure"
+ }
+ },
+ auditLogMode: {
+ tenant: "tenant",
+ entity: "entity",
+ user: "user",
+ customer: "customer"
+ },
aliasFilterType: {
singleEntity: {
value: 'singleEntity',
@@ -239,6 +296,9 @@ export default angular.module('thingsboard.types', [])
dashboard: "DASHBOARD",
alarm: "ALARM"
},
+ aliasEntityType: {
+ current_customer: "CURRENT_CUSTOMER"
+ },
entityTypeTranslations: {
"DEVICE": {
type: 'entity.type-device',
@@ -293,6 +353,10 @@ export default angular.module('thingsboard.types', [])
typePlural: 'entity.type-alarms',
list: 'entity.list-of-alarms',
nameStartsWith: 'entity.alarm-name-starts-with'
+ },
+ "CURRENT_CUSTOMER": {
+ type: 'entity.type-current-customer',
+ list: 'entity.type-current-customer'
}
},
entitySearchDirection: {
diff --git a/ui/src/app/common/utf8-support.js b/ui/src/app/common/utf8-support.js
index 464fa4071e..012b43258f 100644
--- a/ui/src/app/common/utf8-support.js
+++ b/ui/src/app/common/utf8-support.js
@@ -1,5 +1,5 @@
/*
- * Copyright © 2016-2017 The Thingsboard Authors
+ * 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.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
export function utf8Encode(str) {
var result;
diff --git a/ui/src/app/common/utils.service.js b/ui/src/app/common/utils.service.js
index 085a28bad5..53aa1c5c8c 100644
--- a/ui/src/app/common/utils.service.js
+++ b/ui/src/app/common/utils.service.js
@@ -1,5 +1,5 @@
/*
- * Copyright © 2016-2017 The Thingsboard Authors
+ * 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.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
/* eslint-disable import/no-unresolved, import/default */
import materialIconsCodepoints from 'raw-loader!material-design-icons/iconfont/codepoints';
@@ -553,7 +552,9 @@ function Utils($mdColorPalette, $rootScope, $window, $translate, $q, $timeout, t
var aspect = imageAspectMap[urlHashCode];
if (angular.isUndefined(aspect)) {
var testImage = document.createElement('img'); // eslint-disable-line
- testImage.style.visibility = 'hidden';
+ testImage.style.position = 'absolute';
+ testImage.style.left = '-99999px';
+ testImage.style.top = '-99999px';
testImage.onload = function() {
aspect = testImage.width / testImage.height;
document.body.removeChild(testImage); //eslint-disable-line
diff --git a/ui/src/app/component/component-dialog.controller.js b/ui/src/app/component/component-dialog.controller.js
index eacb74ca8b..9bceca99b8 100644
--- a/ui/src/app/component/component-dialog.controller.js
+++ b/ui/src/app/component/component-dialog.controller.js
@@ -1,5 +1,5 @@
/*
- * Copyright © 2016-2017 The Thingsboard Authors
+ * 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.
diff --git a/ui/src/app/component/component-dialog.service.js b/ui/src/app/component/component-dialog.service.js
index c3946c1f5a..cbd3ccbb2e 100644
--- a/ui/src/app/component/component-dialog.service.js
+++ b/ui/src/app/component/component-dialog.service.js
@@ -1,5 +1,5 @@
/*
- * Copyright © 2016-2017 The Thingsboard Authors
+ * 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.
diff --git a/ui/src/app/component/component-dialog.tpl.html b/ui/src/app/component/component-dialog.tpl.html
index 841d7ef69a..5bea1a5335 100644
--- a/ui/src/app/component/component-dialog.tpl.html
+++ b/ui/src/app/component/component-dialog.tpl.html
@@ -1,6 +1,6 @@
-
-
+
+
+
+
diff --git a/ui/src/app/customer/index.js b/ui/src/app/customer/index.js
index d0596d8389..0b155d36fa 100644
--- a/ui/src/app/customer/index.js
+++ b/ui/src/app/customer/index.js
@@ -1,5 +1,5 @@
/*
- * Copyright © 2016-2017 The Thingsboard Authors
+ * 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.
diff --git a/ui/src/app/dashboard/add-dashboard.tpl.html b/ui/src/app/dashboard/add-dashboard.tpl.html
index 79735e0960..6dc9f7a492 100644
--- a/ui/src/app/dashboard/add-dashboard.tpl.html
+++ b/ui/src/app/dashboard/add-dashboard.tpl.html
@@ -1,6 +1,6 @@
-
-
-
\ No newline at end of file
diff --git a/ui/src/app/dashboard/dashboard-card.scss b/ui/src/app/dashboard/dashboard-card.scss
new file mode 100644
index 0000000000..0dac2131f6
--- /dev/null
+++ b/ui/src/app/dashboard/dashboard-card.scss
@@ -0,0 +1,26 @@
+/**
+ * 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.
+ */
+.tb-dashboard-assigned-customers {
+ display: block;
+ display: -webkit-box;
+ height: 34px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ -webkit-line-clamp: 2;
+ -webkit-box-orient: vertical;
+ margin-bottom: 4px;
+}
+
diff --git a/ui/src/app/dashboard/dashboard-card.tpl.html b/ui/src/app/dashboard/dashboard-card.tpl.html
index 636786758e..9e71d2a79a 100644
--- a/ui/src/app/dashboard/dashboard-card.tpl.html
+++ b/ui/src/app/dashboard/dashboard-card.tpl.html
@@ -1,6 +1,6 @@
-{{'dashboard.assignedToCustomer' | translate}} '{{vm.item.assignedCustomer.title}}'
-{{'dashboard.public' | translate}}
+{{'dashboard.assignedToCustomers' | translate}}: '{{vm.item.assignedCustomersText}}'
+{{'dashboard.public' | translate}}
diff --git a/ui/src/app/dashboard/dashboard-fieldset.tpl.html b/ui/src/app/dashboard/dashboard-fieldset.tpl.html
index a54f477d11..f92f5f9575 100644
--- a/ui/src/app/dashboard/dashboard-fieldset.tpl.html
+++ b/ui/src/app/dashboard/dashboard-fieldset.tpl.html
@@ -1,6 +1,6 @@
-
diff --git a/ui/src/app/dashboard/dashboard.controller.js b/ui/src/app/dashboard/dashboard.controller.js
index d4d3a1c939..f672f3f03b 100644
--- a/ui/src/app/dashboard/dashboard.controller.js
+++ b/ui/src/app/dashboard/dashboard.controller.js
@@ -1,5 +1,5 @@
/*
- * Copyright © 2016-2017 The Thingsboard Authors
+ * 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.
diff --git a/ui/src/app/dashboard/dashboard.directive.js b/ui/src/app/dashboard/dashboard.directive.js
index b2f3117a04..8f042856eb 100644
--- a/ui/src/app/dashboard/dashboard.directive.js
+++ b/ui/src/app/dashboard/dashboard.directive.js
@@ -1,5 +1,5 @@
/*
- * Copyright © 2016-2017 The Thingsboard Authors
+ * 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.
@@ -20,36 +20,17 @@ import dashboardFieldsetTemplate from './dashboard-fieldset.tpl.html';
/* eslint-enable import/no-unresolved, import/default */
/*@ngInject*/
-export default function DashboardDirective($compile, $templateCache, $translate, types, toast, customerService, dashboardService) {
+export default function DashboardDirective($compile, $templateCache, $translate, types, toast, dashboardService) {
var linker = function (scope, element) {
var template = $templateCache.get(dashboardFieldsetTemplate);
element.html(template);
-
- scope.isAssignedToCustomer = false;
- scope.isPublic = false;
- scope.assignedCustomer = null;
scope.publicLink = null;
-
scope.$watch('dashboard', function(newVal) {
if (newVal) {
- if (scope.dashboard.customerId && scope.dashboard.customerId.id !== types.id.nullUid) {
- scope.isAssignedToCustomer = true;
- customerService.getShortCustomerInfo(scope.dashboard.customerId.id).then(
- function success(customer) {
- scope.assignedCustomer = customer;
- scope.isPublic = customer.isPublic;
- if (scope.isPublic) {
- scope.publicLink = dashboardService.getPublicDashboardLink(scope.dashboard);
- } else {
- scope.publicLink = null;
- }
- }
- );
+ if (scope.dashboard.publicCustomerId) {
+ scope.publicLink = dashboardService.getPublicDashboardLink(scope.dashboard);
} else {
- scope.isAssignedToCustomer = false;
- scope.isPublic = false;
scope.publicLink = null;
- scope.assignedCustomer = null;
}
}
});
@@ -66,10 +47,12 @@ export default function DashboardDirective($compile, $templateCache, $translate,
scope: {
dashboard: '=',
isEdit: '=',
+ customerId: '=',
dashboardScope: '=',
theForm: '=',
- onAssignToCustomer: '&',
onMakePublic: '&',
+ onMakePrivate: '&',
+ onManageAssignedCustomers: '&',
onUnassignFromCustomer: '&',
onExportDashboard: '&',
onDeleteDashboard: '&'
diff --git a/ui/src/app/dashboard/dashboard.routes.js b/ui/src/app/dashboard/dashboard.routes.js
index 92bb36220f..ccb43c708f 100644
--- a/ui/src/app/dashboard/dashboard.routes.js
+++ b/ui/src/app/dashboard/dashboard.routes.js
@@ -1,5 +1,5 @@
/*
- * Copyright © 2016-2017 The Thingsboard Authors
+ * 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.
diff --git a/ui/src/app/dashboard/dashboard.scss b/ui/src/app/dashboard/dashboard.scss
index daae8ecfc3..224dcf7e4a 100644
--- a/ui/src/app/dashboard/dashboard.scss
+++ b/ui/src/app/dashboard/dashboard.scss
@@ -1,5 +1,5 @@
/**
- * Copyright © 2016-2017 The Thingsboard Authors
+ * 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.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
@import "~compass-sass-mixins/lib/compass";
@import '../../scss/constants';
diff --git a/ui/src/app/dashboard/dashboard.tpl.html b/ui/src/app/dashboard/dashboard.tpl.html
index fab46346da..9626509a51 100644
--- a/ui/src/app/dashboard/dashboard.tpl.html
+++ b/ui/src/app/dashboard/dashboard.tpl.html
@@ -1,6 +1,6 @@
+
+
+
\ No newline at end of file
diff --git a/ui/src/app/dashboard/states/dashboard-state-dialog.controller.js b/ui/src/app/dashboard/states/dashboard-state-dialog.controller.js
index 8af5a77fe8..8d46ee42e9 100644
--- a/ui/src/app/dashboard/states/dashboard-state-dialog.controller.js
+++ b/ui/src/app/dashboard/states/dashboard-state-dialog.controller.js
@@ -1,5 +1,5 @@
/*
- * Copyright © 2016-2017 The Thingsboard Authors
+ * 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.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
/*@ngInject*/
export default function DashboardStateDialogController($scope, $mdDialog, $filter, dashboardUtils, isAdd, allStates, state) {
diff --git a/ui/src/app/dashboard/states/dashboard-state-dialog.tpl.html b/ui/src/app/dashboard/states/dashboard-state-dialog.tpl.html
index 3f9fb4336d..3c31ebf99b 100644
--- a/ui/src/app/dashboard/states/dashboard-state-dialog.tpl.html
+++ b/ui/src/app/dashboard/states/dashboard-state-dialog.tpl.html
@@ -1,6 +1,6 @@
-
diff --git a/ui/src/app/entity/alias/aliases-entity-select-panel.controller.js b/ui/src/app/entity/alias/aliases-entity-select-panel.controller.js
index 90248b2d57..6ff7863964 100644
--- a/ui/src/app/entity/alias/aliases-entity-select-panel.controller.js
+++ b/ui/src/app/entity/alias/aliases-entity-select-panel.controller.js
@@ -1,5 +1,5 @@
/*
- * Copyright © 2016-2017 The Thingsboard Authors
+ * 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.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
/*@ngInject*/
export default function AliasesEntitySelectPanelController(mdPanelRef, $scope, $filter, types, aliasController, onEntityAliasesUpdate) {
diff --git a/ui/src/app/entity/alias/aliases-entity-select-panel.tpl.html b/ui/src/app/entity/alias/aliases-entity-select-panel.tpl.html
index d197d0bd9c..bfce77cf6a 100644
--- a/ui/src/app/entity/alias/aliases-entity-select-panel.tpl.html
+++ b/ui/src/app/entity/alias/aliases-entity-select-panel.tpl.html
@@ -1,6 +1,6 @@
-
alias.no-entity-filter-specified
diff --git a/ui/src/app/entity/entity-filter.directive.js b/ui/src/app/entity/entity-filter.directive.js
index 3cede93b39..0c8f6468f0 100644
--- a/ui/src/app/entity/entity-filter.directive.js
+++ b/ui/src/app/entity/entity-filter.directive.js
@@ -1,5 +1,5 @@
/*
- * Copyright © 2016-2017 The Thingsboard Authors
+ * 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.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
/* eslint-disable import/no-unresolved, import/default */
import entityFilterTemplate from './entity-filter.tpl.html';
diff --git a/ui/src/app/entity/entity-filter.scss b/ui/src/app/entity/entity-filter.scss
index 7e998ca674..bbaa108e09 100644
--- a/ui/src/app/entity/entity-filter.scss
+++ b/ui/src/app/entity/entity-filter.scss
@@ -1,5 +1,5 @@
/**
- * Copyright © 2016-2017 The Thingsboard Authors
+ * 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.
@@ -13,7 +13,6 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
.tb-entity-filter {
#relationsQueryFilter {
diff --git a/ui/src/app/entity/entity-filter.tpl.html b/ui/src/app/entity/entity-filter.tpl.html
index 9f62454915..f9aac3cb78 100644
--- a/ui/src/app/entity/entity-filter.tpl.html
+++ b/ui/src/app/entity/entity-filter.tpl.html
@@ -1,6 +1,6 @@
-
-
-
+
+ refresh
+
+ {{ 'action.refresh' | translate }}
+
+
-