Repository: nifi-registry Updated Branches: refs/heads/master a2f639f37 -> 247985ada
http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/247985ad/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.js ---------------------------------------------------------------------- diff --git a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.js b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.js index e9fbb5f..f796f7a 100644 --- a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.js +++ b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.js @@ -20,105 +20,108 @@ var ngRouter = require('@angular/router'); var fdsDialogsModule = require('@fluid-design-system/dialogs'); var fdsSnackBarsModule = require('@fluid-design-system/snackbars'); var NfRegistryApi = require('nifi-registry/services/nf-registry.api.js'); +var NfStorage = require('nifi-registry/services/nf-storage.service.js'); +var rxjs = require('rxjs/Rx'); require('rxjs/add/operator/catch'); require('rxjs/add/operator/map'); -function filterData(data, searchTerm, ignoreCase) { - var field = ''; - if (searchTerm.indexOf(":") > -1) { - field = searchTerm.split(':')[0].trim(); - searchTerm = searchTerm.split(':')[1].trim(); - } - var filter = searchTerm ? (ignoreCase ? searchTerm.toLowerCase() : searchTerm) : ''; - - if (filter) { - data = data.filter(function (item) { - var res = Object.keys(item).find(function (key) { - if (key !== field && field !== '') { - return false; - } - var preItemValue = ('' + item[key]); - var itemValue = ignoreCase ? preItemValue.toLowerCase() : preItemValue; - return itemValue.indexOf(filter) > -1; - }); - return !(typeof res === 'undefined'); - }); - } - return data; -}; - /** * NfRegistryService constructor. * - * @param TdDataTableService The covalent data table service module. - * @param NfRegistryApi The registry API module. - * @param Router The angular router module. - * @param FdsDialogService The FDS dialog service. - * @param FdsSnackBarService The FDS snack bar service module. + * @param nfRegistryApi The api service. + * @param nfStorage A wrapper for the browser's local storage. + * @param tdDataTableService The covalent data table service module. + * @param router The angular router module. + * @param fdsDialogService The FDS dialog service. + * @param fdsSnackBarService The FDS snack bar service module. * @constructor */ -function NfRegistryService(TdDataTableService, NfRegistryApi, Router, FdsDialogService, FdsSnackBarService) { - this.router = Router; - this.dialogService = FdsDialogService; - this.snackBarService = FdsSnackBarService; +function NfRegistryService(nfRegistryApi, nfStorage, tdDataTableService, router, fdsDialogService, fdsSnackBarService) { + this.router = router; + this.api = nfRegistryApi; + this.nfStorage = nfStorage; + this.dialogService = fdsDialogService; + this.snackBarService = fdsSnackBarService; this.registry = { name: "Nifi Registry" }; - this.api = NfRegistryApi; this.bucket = {}; this.buckets = []; this.droplet = {}; this.droplets = []; + this.currentUser = {}; this.user = {}; + this.group = {}; this.users = []; + this.groups = []; this.alerts = []; this.explorerViewType = ''; this.perspective = ''; this.breadCrumbState = 'out'; - this.dataTableService = TdDataTableService; + this.dataTableService = tdDataTableService; this.filteredDroplets = []; this.dropletActions = [{ - 'name': 'Delete', - 'icon': 'fa fa-trash', - 'tooltip': 'Delete' + name: 'Delete', + icon: 'fa fa-trash', + tooltip: 'Delete' }]; this.dropletColumns = [ - {name: 'name', label: 'Name', sortable: true}, - {name: 'updated', label: 'Updated', sortable: true} + { + name: 'name', + label: 'Name', + sortable: true + }, + { + name: 'updated', + label: 'Updated', + sortable: true + } ]; this.autoCompleteDroplets = []; this.dropletsSearchTerms = []; this.filteredBuckets = []; this.bucketColumns = [ - {name: 'name', label: 'Bucket Name', sortable: true, tooltip: 'Sort Buckets by name.'} + { + name: 'name', + label: 'Bucket Name', + sortable: true, + tooltip: 'Sort Buckets by name.' + } ]; this.allBucketsSelected = false; this.autoCompleteBuckets = []; this.selectedBuckets = []; this.bucketsSearchTerms = []; - this.disableMultiBucketActions = true; + this.isMultiBucketActionsDisabled = true; this.filteredUsers = []; + this.filteredUserGroups = []; this.userColumns = [ - {name: 'status', label: 'Status', sortable: true, tooltip: 'User Status.', width: 18}, - {name: 'name', label: 'Name', sortable: true, tooltip: 'User name.', width: 30}, - {name: 'provider', label: 'Provider', sortable: true, tooltip: 'Authentication provider.', width: 30} + { + name: 'identity', + label: 'Display Name', + sortable: true, + tooltip: 'User name.', + width: 100 + } ]; - this.allUsersSelected = false; - this.autoCompleteUsers = []; + this.allUsersAndGroupsSelected = false; + this.autoCompleteUsersAndGroups = []; this.selectedUsers = []; this.usersSearchTerms = []; + this.isMultiUserActionsDisabled = true; + this.isMultiUserGroupActionsDisabled = false; }; NfRegistryService.prototype = { constructor: NfRegistryService, /** - * Set the state for the breadcrumb animations. + * Set the `breadCrumbState` for the breadcrumb animations. * - * @param {string} state The state. Valid values are 'in' or 'out'. + * @param {string} state The state. Valid values are 'in' or 'out'. */ setBreadcrumbState: function (state) { this.breadCrumbState = state; @@ -156,7 +159,7 @@ NfRegistryService.prototype = { /** * Generates the droplet grid-list explorer component's sorting menu options. * - * @param col One of the available `dropletColumns`. + * @param col One of the available `dropletColumns`. * @returns {string} */ generateSortMenuLabels: function (col) { @@ -191,31 +194,20 @@ NfRegistryService.prototype = { function (accept) { if (accept) { self.api.deleteDroplet(droplet.link.href).subscribe(function (response) { - if (response.link === null) { - self.droplets = self.droplets.filter(function (d) { - return (d.identifier !== droplet.identifier) ? true : false - }); - var snackBarRef = self.snackBarService.openCoaster({ - title: 'Success', - message: 'All versions of this ' + droplet.type.toLowerCase() + ' have been deleted.', - verticalPosition: 'bottom', - horizontalPosition: 'right', - icon: 'fa fa-check-circle-o', - color: '#1EB475', - duration: 3000 - }); - self.droplet = {}; - self.filterDroplets(); - } else { - var snackBarRef = self.snackBarService.openCoaster({ - title: 'Error', - message: 'Error deleting ' + droplet.name + '.', - verticalPosition: 'bottom', - horizontalPosition: 'right', - icon: 'fa fa-times-circle-o', - color: '#EF6162' - }); - } + self.droplets = self.droplets.filter(function (d) { + return (d.identifier !== droplet.identifier) ? true : false + }); + var snackBarRef = self.snackBarService.openCoaster({ + title: 'Success', + message: 'All versions of this ' + droplet.type.toLowerCase() + ' have been deleted.', + verticalPosition: 'bottom', + horizontalPosition: 'right', + icon: 'fa fa-check-circle-o', + color: '#1EB475', + duration: 3000 + }); + self.droplet = {}; + self.filterDroplets(); }); } }); @@ -234,7 +226,7 @@ NfRegistryService.prototype = { }, /** - * Sort `droplets` by `column`. + * Sort `filteredDroplets` by `column`. * * @param column The column to sort by. */ @@ -270,7 +262,6 @@ NfRegistryService.prototype = { for (var i = 0; i < arrayLength; i++) { if (this.dropletColumns[i].sortable === true) { sortBy = this.dropletColumns[i].name; - this.activeDropletColumn = this.dropletColumns[i]; //only one column can be actively sorted so we reset all to inactive this.dropletColumns.forEach(function (c) { c.active = false; @@ -293,7 +284,7 @@ NfRegistryService.prototype = { } for (var i = 0; i < this.dropletsSearchTerms.length; i++) { - newData = filterData(newData, this.dropletsSearchTerms[i], true, this.activeDropletColumn.name); + newData = this.filterData(newData, this.dropletsSearchTerms[i], true, sortBy); } newData = this.dataTableService.sortData(newData, sortBy, sortOrder); @@ -302,7 +293,7 @@ NfRegistryService.prototype = { }, /** - * Generates the auto complete options for the droplet filter. + * Generates the `autoCompleteDroplets` options for the droplet filter. */ getAutoCompleteDroplets: function () { var self = this; @@ -326,7 +317,7 @@ NfRegistryService.prototype = { case 'delete': this.dialogService.openConfirm({ title: 'Delete Bucket', - message: 'All versions of all items will be deleted.', + message: 'All items stored in this bucket will be deleted as well.', cancelButton: 'Cancel', acceptButton: 'Delete', acceptButtonColor: 'fds-warn' @@ -334,31 +325,20 @@ NfRegistryService.prototype = { function (accept) { if (accept) { self.api.deleteBucket(bucket.identifier).subscribe(function (response) { - if (response.link === null) { - self.buckets = self.buckets.filter(function (b) { - return b.identifier !== bucket.identifier; - }); - var snackBarRef = self.snackBarService.openCoaster({ - title: 'Success', - message: 'All versions of all items in this bucket, as well as the bucket, have been deleted.', - verticalPosition: 'bottom', - horizontalPosition: 'right', - icon: 'fa fa-check-circle-o', - color: '#1EB475', - duration: 3000 - }); - self.bucket = {}; - self.filterBuckets(); - } else { - var snackBarRef = self.snackBarService.openCoaster({ - title: 'Error', - message: 'Error deleting ' + bucket.name + '.', - verticalPosition: 'bottom', - horizontalPosition: 'right', - icon: 'fa fa-times-circle-o', - color: '#EF6162' - }); - } + self.buckets = self.buckets.filter(function (b) { + return b.identifier !== bucket.identifier; + }); + var snackBarRef = self.snackBarService.openCoaster({ + title: 'Success', + message: 'All versions of all items in this bucket, as well as the bucket, have been deleted.', + verticalPosition: 'bottom', + horizontalPosition: 'right', + icon: 'fa fa-check-circle-o', + color: '#1EB475', + duration: 3000 + }); + self.bucket = {}; + self.filterBuckets(); }); } }); @@ -372,7 +352,7 @@ NfRegistryService.prototype = { }, /** - * Filter buckets. + * Filter buckets and sets the `isMultiBucketActionsDisabled` property accordingly. * * @param {string} sortBy The column name to sort `bucketColumns` by. * @param {string} sortOrder The order. Either 'ASC' or 'DES' @@ -389,7 +369,6 @@ NfRegistryService.prototype = { for (var i = 0; i < arrayLength; i++) { if (this.bucketColumns[i].sortable === true) { sortBy = this.bucketColumns[i].name; - this.activeBucketColumn = this.bucketColumns[i]; //only one column can be actively sorted so we reset all to inactive this.bucketColumns.forEach(function (c) { c.active = false; @@ -405,7 +384,7 @@ NfRegistryService.prototype = { var newData = this.buckets; for (var i = 0; i < this.bucketsSearchTerms.length; i++) { - newData = filterData(newData, this.bucketsSearchTerms[i], true, this.activeBucketColumn.name); + newData = this.filterData(newData, this.bucketsSearchTerms[i], true, sortBy); } newData = this.dataTableService.sortData(newData, sortBy, sortOrder); @@ -418,13 +397,13 @@ NfRegistryService.prototype = { } }); - this.disableMultiBucketActions = (selected > 0) ? false : true; + this.isMultiBucketActionsDisabled = (selected > 0) ? false : true; this.getAutoCompleteBuckets(); }, /** - * Generates the auto complete options for the bucket filter. + * Generates the `autoCompleteBuckets` options for the bucket filter. */ getAutoCompleteBuckets: function () { var self = this; @@ -437,7 +416,7 @@ NfRegistryService.prototype = { }, /** - * Sort `buckets` by `column`. + * Sort `filteredBuckets` by `column`. * * @param column The column to sort by. */ @@ -446,7 +425,6 @@ NfRegistryService.prototype = { // toggle column sort order var sortOrder = column.sortOrder = (column.sortOrder === 'ASC') ? 'DESC' : 'ASC'; this.filterBuckets(column.name, sortOrder); - this.activeBucketsColumn = column; //only one column can be actively sorted so we reset all to inactive this.bucketColumns.forEach(function (c) { c.active = false; @@ -457,7 +435,8 @@ NfRegistryService.prototype = { }, /** - * Returns true if each bucket in the `filteredBuckets` are selected. + * Returns true if each bucket in the `filteredBuckets` are selected and sets the `isMultiBucketActionsDisabled` + * property accordingly. * * @returns {boolean} */ @@ -473,12 +452,12 @@ NfRegistryService.prototype = { } }); - this.disableMultiBucketActions = (selected > 0) ? false : true; + this.isMultiBucketActionsDisabled = (selected > 0) ? false : true; return allSelected; }, /** - * Checks all filtered buckets checked state and sets the `allBucketsSelected` + * Checks each of the `filteredBuckets`'s `checked` property state and sets the `allBucketsSelected` * property accordingly. */ determineAllBucketsSelectedState: function () { @@ -502,23 +481,25 @@ NfRegistryService.prototype = { }, /** - * Sets the `checked` property of each filtered bucket to true. + * Sets the `checked` property of each filtered bucket to true and sets + * the `isMultiBucketActionsDisabled` property accordingly. */ selectAllBuckets: function () { this.filteredBuckets.forEach(function (c) { c.checked = true; }); - this.disableMultiBucketActions = false; + this.isMultiBucketActionsDisabled = false; }, /** - * Sets the `checked` property of each filtered bucket to false. + * Sets the `checked` property of each filtered bucket to false and sets + * the `isMultiBucketActionsDisabled` property accordingly. */ deselectAllBuckets: function () { this.filteredBuckets.forEach(function (c) { c.checked = false; }); - this.disableMultiBucketActions = true; + this.isMultiBucketActionsDisabled = true; }, /** @@ -533,6 +514,7 @@ NfRegistryService.prototype = { this.bucketsSearchTerms.splice(index, 1); } this.filterBuckets(); + this.determineAllBucketsSelectedState(); }, /** @@ -543,6 +525,7 @@ NfRegistryService.prototype = { bucketsSearchAdd: function (searchTerm) { this.bucketsSearchTerms.push(searchTerm); this.filterBuckets(); + this.determineAllBucketsSelectedState(); }, /** @@ -562,43 +545,37 @@ NfRegistryService.prototype = { self.filteredBuckets.forEach(function (filteredBucket) { if (filteredBucket.checked) { self.api.deleteBucket(filteredBucket.identifier).subscribe(function (response) { - if (response.link === null) { - self.buckets = self.buckets.filter(function (bucket) { - return bucket.identifier !== filteredBucket.identifier; - }); - var snackBarRef = self.snackBarService.openCoaster({ - title: 'Success', - message: 'All versions of all items in ' + filteredBucket.name + ' have been deleted.', - verticalPosition: 'bottom', - horizontalPosition: 'right', - icon: 'fa fa-check-circle-o', - color: '#1EB475', - duration: 3000 - }); - self.filterBuckets(); - self.allBucketsSelected = false; - } else { - var snackBarRef = self.snackBarService.openCoaster({ - title: 'Error', - message: 'Error deleting ' + filteredBucket.name + '.', - verticalPosition: 'bottom', - horizontalPosition: 'right', - icon: 'fa fa-times-circle-o', - color: '#EF6162' - }); - } + self.buckets = self.buckets.filter(function (bucket) { + return bucket.identifier !== filteredBucket.identifier; + }); + var snackBarRef = self.snackBarService.openCoaster({ + title: 'Success', + message: 'All versions of all items in ' + filteredBucket.name + ' have been deleted.', + verticalPosition: 'bottom', + horizontalPosition: 'right', + icon: 'fa fa-check-circle-o', + color: '#1EB475', + duration: 3000 + }); + self.filterBuckets(); }); } }); + self.determineAllBucketsSelectedState(); } }); }, - sortUsers: function (sortEvent, column) { + /** + * Sort `users` and `groups` by `column`. + * + * @param column The column to sort by. + */ + sortUsersAndGroups: function (sortEvent, column) { if (column.sortable) { var sortBy = column.name; var sortOrder = column.sortOrder = (column.sortOrder === 'ASC') ? 'DESC' : 'ASC'; - this.filterUsers(sortBy, sortOrder); + this.filterUsersAndGroups(sortBy, sortOrder); //only one column can be actively sorted so we reset all to inactive this.userColumns.forEach(function (c) { @@ -609,90 +586,384 @@ NfRegistryService.prototype = { } }, + /** + * Loads the current user and updates the current user locally. + * + * @returns xhr + */ + loadCurrentUser: function () { + var self = this; + // get the current user + return rxjs.Observable.of(this.api.loadCurrentUser().subscribe(function (currentUser) { + // if the user is logged, we want to determine if they were logged in using a certificate + if (currentUser.status !== "UNKNOWN") { + // render the users name + self.currentUser = currentUser; + + // render the logout button if there is a token locally + if (self.nfStorage.getItem('jwt') !== null) { + self.currentUser.canLogout = true; + } + } else { + // set the anonymous user label + self.nfRegistryService.currentUser.identity = 'Anonymous'; + } + })); + }, + + /** + * Adds a `searchTerm` to the `usersSearchTerms` and filters the `users` amd `groups`. + * + * @param {string} searchTerm The search term to add. + */ usersSearchRemove: function (searchTerm) { //only remove the first occurrence of the search term var index = this.usersSearchTerms.indexOf(searchTerm); if (index !== -1) { this.usersSearchTerms.splice(index, 1); } - this.filterUsers(); + this.filterUsersAndGroups(); + this.determineAllUsersAndGroupsSelectedState(); }, + /** + * Removes a `searchTerm` from the `usersSearchTerms` and filters the `users` amd `groups`. + * + * @param {string} searchTerm The search term to remove. + */ usersSearchAdd: function (searchTerm) { this.usersSearchTerms.push(searchTerm); - this.filterUsers(); + this.filterUsersAndGroups(); + this.determineAllUsersAndGroupsSelectedState(); }, - filterUsers: function (sortBy, sortOrder) { - if (this.allUsersSelected) { - this.toggleUsersSelectAll(); + /** + * Filter users and groups. + * + * @param {string} [sortBy] The column name to sort `userGroupsColumns` by. + * @param {string} [sortOrder] The order. Either 'ASC' or 'DES' + */ + filterUsersAndGroups: function (sortBy, sortOrder) { + // if `sortOrder` is `undefined` then use 'ASC' + if (sortOrder === undefined) { + sortOrder = 'ASC' + } + // if `sortBy` is `undefined` then find the first sortable column in `dropletColumns` + if (sortBy === undefined) { + var arrayLength = this.userColumns.length; + for (var i = 0; i < arrayLength; i++) { + if (this.userColumns[i].sortable === true) { + sortBy = this.userColumns[i].name; + //only one column can be actively sorted so we reset all to inactive + this.userColumns.forEach(function (c) { + c.active = false; + }); + //and set this column as the actively sorted column + this.userColumns[i].active = true; + this.userColumns[i].sortOrder = sortOrder; + break; + } + } } - this.deselectAllUsers(); - var newData = this.users; + + var newUsersData = this.users; + var newUserGroupsData = this.groups; for (var i = 0; i < this.usersSearchTerms.length; i++) { - newData = filterData(newData, this.usersSearchTerms[i], true); + newUsersData = this.filterData(newUsersData, this.usersSearchTerms[i], true); } - newData = this.dataTableService.sortData(newData, sortBy, sortOrder); - newData = this.dataTableService.pageData(newData, this.usersFromRow, this.usersCurrentPage * this.usersPageSize); - this.filteredUsers = newData; - this.getAutoCompleteUsers(); + + newUsersData = this.dataTableService.sortData(newUsersData, sortBy, sortOrder); + this.filteredUsers = newUsersData; + + for (var i = 0; i < this.usersSearchTerms.length; i++) { + newUserGroupsData = this.filterData(newUserGroupsData, this.usersSearchTerms[i], true); + } + + newUserGroupsData = this.dataTableService.sortData(newUserGroupsData, sortBy, sortOrder); + this.filteredUserGroups = newUserGroupsData; + + this.getAutoCompleteUserAndGroups(); }, - toggleUserSelect: function (row) { - if (this.allFilteredUsersSelected()) { - this.allUsersSelected = true; - } else { - this.allUsersSelected = false; + /** + * Checks each of the `filteredUsers` and each of the `filteredUserGroups` `checked` property state and sets + * the `allUsersAndGroupsSelected`, `isMultiUserGroupActionsDisabled`, and the `isMultiUserActionsDisabled` + * properties accordingly. + */ + determineAllUsersAndGroupsSelectedState: function () { + var selected = 0; + var allSelected = true; + this.isMultiUserGroupActionsDisabled = false; + this.filteredUserGroups.forEach(function (c) { + if (c.checked) { + selected++; + } + if (c.checked === undefined || c.checked === false) { + allSelected = false; + } + }); + + if (selected > 0) { + this.isMultiUserGroupActionsDisabled = true; } + + this.filteredUsers.forEach(function (c) { + if (c.checked) { + selected++; + } + if (c.checked === undefined || c.checked === false) { + allSelected = false; + } + }); + this.isMultiUserActionsDisabled = (selected > 0) ? false : true; + this.allUsersAndGroupsSelected = allSelected; }, + /** + * Checks the `allUsersAndGroupsSelected` property state and either selects + * or deselects all `filteredUsers` and each `filteredUserGroups`. + */ toggleUsersSelectAll: function () { - if (this.allUsersSelected) { - this.selectAllUsers(); + if (this.allUsersAndGroupsSelected) { + this.selectAllUsersAndGroups(); } else { - this.deselectAllUsers(); + this.deselectAllUsersAndGroups(); } }, - selectAllUsers: function () { + /** + * Sets the `checked` property of each `filteredUsers` and each `filteredUserGroups` to true and sets + * the `allUsersAndGroupsSelected`, `isMultiUserGroupActionsDisabled`, and the `isMultiUserActionsDisabled` + * properties accordingly. + */ + selectAllUsersAndGroups: function () { this.filteredUsers.forEach(function (c) { c.checked = true; }); + this.filteredUserGroups.forEach(function (c) { + c.checked = true; + }); + this.isMultiUserGroupActionsDisabled = (this.filteredUserGroups.length > 0) ? true : false; + this.allUsersAndGroupsSelected = true; + this.isMultiUserActionsDisabled = false; }, - deselectAllUsers: function () { + /** + * Sets the `checked` property of each `filteredUsers` and each `filteredUserGroups` to false and sets + * the `allUsersAndGroupsSelected`, `isMultiUserGroupActionsDisabled`, and the `isMultiUserActionsDisabled` + * properties accordingly. + */ + deselectAllUsersAndGroups: function () { this.filteredUsers.forEach(function (c) { c.checked = false; }); - }, - allFilteredUsersSelected: function () { - var allFilteredUsersSelected = true; - this.filteredUsers.forEach(function (c) { - if (c.checked === undefined || c.checked === false) { - allFilteredUsersSelected = false; - } + this.filteredUserGroups.forEach(function (c) { + c.checked = false; }); - - return allFilteredUsersSelected; + this.allUsersAndGroupsSelected = false; + this.isMultiUserGroupActionsDisabled = false; + this.isMultiUserActionsDisabled = true; }, - getAutoCompleteUsers: function () { + /** + * Generates the `autoCompleteUsersAndGroups` options for the users and groups data table filter. + */ + getAutoCompleteUserAndGroups: function () { var self = this; - this.autoCompleteUsers = []; + this.autoCompleteUsersAndGroups = []; this.userColumns.forEach(function (c) { - self.filteredUsers.forEach(function (r) { - (r[c.name.toLowerCase()]) ? self.autoCompleteUsers.push(r[c.name.toLowerCase()].toString()) : ''; + var usersAndGroups = self.filteredUsers.concat(self.filteredUserGroups); + usersAndGroups.forEach(function (r) { + (r[c.name.toLowerCase()]) ? self.autoCompleteUsersAndGroups.push(r[c.name.toLowerCase()].toString()) : ''; }); }); }, + /** + * Execute the given user action. + * + * @param action The action object. + * @param user The user object the `action` will act upon. + */ + executeUserAction: function (action, user) { + var self = this; + switch (action.name.toLowerCase()) { + case 'delete': + this.dialogService.openConfirm({ + title: 'Delete User', + message: 'This user will lose all access to the registry.', + cancelButton: 'Cancel', + acceptButton: 'Delete', + acceptButtonColor: 'fds-warn' + }).afterClosed().subscribe( + function (accept) { + if (accept) { + self.api.deleteUser(user.identifier).subscribe(function (response) { + self.users = self.users.filter(function (u) { + return u.identifier !== user.identifier; + }); + var snackBarRef = self.snackBarService.openCoaster({ + title: 'Success', + message: 'User: ' + user.identity + ' has been deleted.', + verticalPosition: 'bottom', + horizontalPosition: 'right', + icon: 'fa fa-check-circle-o', + color: '#1EB475', + duration: 3000 + }); + self.filterUsersAndGroups(); + }); + } + }); + break; + case 'permissions': + this.router.navigateByUrl('/nifi-registry/administration/users(' + action.type + ':user/' + action.name + '/' + user.identifier + ')'); + break; + } + }, + + /** + * Execute the given group action. + * + * @param action The action object. + * @param group The group object the `action` will act upon. + */ + executeGroupAction: function (action, group) { + var self = this; + this.group = group; + switch (action.name.toLowerCase()) { + case 'delete': + this.dialogService.openConfirm({ + title: 'Delete Group', + message: 'All policies granted to this group will be deleted as well.', + cancelButton: 'Cancel', + acceptButton: 'Delete', + acceptButtonColor: 'fds-warn' + }).afterClosed().subscribe( + function (accept) { + if (accept) { + self.api.deleteUserGroup(group.identifier).subscribe(function (response) { + self.groups = self.groups.filter(function (u) { + return u.identifier !== group.identifier; + }); + var snackBarRef = self.snackBarService.openCoaster({ + title: 'Success', + message: 'Group: ' + group.identity + ' has been deleted.', + verticalPosition: 'bottom', + horizontalPosition: 'right', + icon: 'fa fa-check-circle-o', + color: '#1EB475', + duration: 3000 + }); + self.filterUsersAndGroups(); + }); + } + }); + break; + case 'permissions': + this.router.navigateByUrl('/nifi-registry/administration/users(' + action.type + ':group/' + action.name + '/' + group.identifier + ')'); + break; + } + }, + + /** + * Deletes all selected `filteredUserGroups` and `filteredUsers` and sets the `allUsersAndGroupsSelected` + * property accordingly. + */ + deleteSelectedUsersAndGroups: function () { + var self = this; + this.dialogService.openConfirm({ + title: 'Delete Users/Groups', + message: 'The selected users will lose all access to the registry and all policies granted to the selected groups will be deleted.', + cancelButton: 'Cancel', + acceptButton: 'Delete', + acceptButtonColor: 'fds-warn' + }).afterClosed().subscribe( + function (accept) { + if (accept) { + self.filteredUserGroups.forEach(function (filteredUserGroup) { + if (filteredUserGroup.checked) { + self.api.deleteUserGroup(filteredUserGroup.identifier).subscribe(function (response) { + self.groups = self.groups.filter(function (u) { + return u.identifier !== filteredUserGroup.identifier; + }); + var snackBarRef = self.snackBarService.openCoaster({ + title: 'Success', + message: 'User group: ' + filteredUserGroup.identity + ' has been deleted.', + verticalPosition: 'bottom', + horizontalPosition: 'right', + icon: 'fa fa-check-circle-o', + color: '#1EB475', + duration: 3000 + }); + self.filterUsersAndGroups(); + }); + } + }); + self.filteredUsers.forEach(function (filteredUser) { + if (filteredUser.checked) { + self.api.deleteUser(filteredUser.identifier).subscribe(function (response) { + self.users = self.users.filter(function (u) { + return u.identifier !== filteredUser.identifier; + }); + var snackBarRef = self.snackBarService.openCoaster({ + title: 'Success', + message: 'User: ' + filteredUser.identity + ' has been deleted.', + verticalPosition: 'bottom', + horizontalPosition: 'right', + icon: 'fa fa-check-circle-o', + color: '#1EB475', + duration: 3000 + }); + self.filterUsersAndGroups(); + }); + } + }); + self.determineAllUsersAndGroupsSelectedState(); + } + }); + }, + + /** + * Utility method that performs the custom search capability for data tables. + * + * @param data The data to search. + * @param searchTerm The term we are looking for. + * @param ignoreCase Ignore case. + * @returns {*} + */ + filterData: function(data, searchTerm, ignoreCase) { + var field = ''; + if (searchTerm.indexOf(":") > -1) { + field = searchTerm.split(':')[0].trim(); + searchTerm = searchTerm.split(':')[1].trim(); + } + var filter = searchTerm ? (ignoreCase ? searchTerm.toLowerCase() : searchTerm) : ''; + + if (filter) { + data = data.filter(function (item) { + var res = Object.keys(item).find(function (key) { + if (key !== field && field !== '') { + return false; + } + var preItemValue = ('' + item[key]); + var itemValue = ignoreCase ? preItemValue.toLowerCase() : preItemValue; + return itemValue.indexOf(filter) > -1; + }); + return !(typeof res === 'undefined'); + }); + } + return data; + } + //</editor-fold> }; NfRegistryService.parameters = [ - covalentCore.TdDataTableService, NfRegistryApi, + NfStorage, + covalentCore.TdDataTableService, ngRouter.Router, fdsDialogsModule.FdsDialogService, fdsSnackBarsModule.FdsSnackBarService http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/247985ad/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.spec.js ---------------------------------------------------------------------- diff --git a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.spec.js b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.spec.js index bd3f898..2b9d92f 100644 --- a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.spec.js +++ b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.service.spec.js @@ -17,6 +17,7 @@ var NfRegistryRoutes = require('nifi-registry/nf-registry.routes.js'); var ngCoreTesting = require('@angular/core/testing'); +var ngCommonHttpTesting = require('@angular/common/http/testing'); var ngHttpTesting = require('@angular/http/testing'); var ngCommon = require('@angular/common'); var FdsDemo = require('nifi-registry/components/fluid-design-system/fds-demo.js'); @@ -27,9 +28,10 @@ var NfPageNotFoundComponent = require('nifi-registry/components/page-not-found/n var NfRegistryExplorer = require('nifi-registry/components/explorer/nf-registry-explorer.js'); var NfRegistryAdministration = require('nifi-registry/components/administration/nf-registry-administration.js'); var NfRegistryUsersAdministration = require('nifi-registry/components/administration/users/nf-registry-users-administration.js'); -var NfRegistryAddUser = require('nifi-registry/components/administration/users/add/nf-registry-add-user.js'); +var NfRegistryAddUser = require('nifi-registry/components/administration/users/dialogs/add-user/nf-registry-add-user.js'); var NfRegistryUserDetails = require('nifi-registry/components/administration/users/details/nf-registry-user-details.js'); var NfRegistryUserPermissions = require('nifi-registry/components/administration/users/permissions/nf-registry-user-permissions.js'); +var NfRegistryUserGroupPermissions = require('nifi-registry/components/administration/user-group/permissions/nf-registry-user-group-permissions.js'); var NfRegistryBucketPermissions = require('nifi-registry/components/administration/workflow/buckets/permissions/nf-registry-bucket-permissions.js'); var NfRegistryWorkflowAdministration = require('nifi-registry/components/administration/workflow/nf-registry-workflow-administration.js'); var NfRegistryGridListViewer = require('nifi-registry/components/explorer/grid-list/registry/nf-registry-grid-list-viewer.js'); @@ -41,6 +43,10 @@ var ngHttp = require('@angular/http'); var rxjs = require('rxjs/Rx'); var fdsDialogsModule = require('@fluid-design-system/dialogs'); var ngRouter = require('@angular/router'); +var ngCommonHttp = require('@angular/common/http'); +var NfRegistryTokenInterceptor = require('nifi-registry/services/nf-registry.token.interceptor.js'); +var NfRegistryAuthService = require('nifi-registry/services/nf-registry.auth.service.js'); +var NfStorage = require('nifi-registry/services/nf-storage.service.js'); describe('NfRegistry Service isolated unit tests', function () { var comp; @@ -182,7 +188,6 @@ describe('NfRegistry Service isolated unit tests', function () { var filterBucketsCall = nfRegistryService.filterBuckets.calls.first(); expect(filterBucketsCall.args[0]).toBe('name'); expect(filterBucketsCall.args[1]).toBe('ASC'); - expect(nfRegistryService.activeBucketsColumn).toBe(column); }); it('should generate the auto complete options for the droplet filter.', function () { @@ -241,7 +246,7 @@ describe('NfRegistry Service isolated unit tests', function () { //assertions expect(allSelected).toBe(false); - expect(nfRegistryService.disableMultiBucketActions).toBe(true); + expect(nfRegistryService.isMultiBucketActionsDisabled).toBe(true); }); it('should check if all buckets are selected and return true.', function () { @@ -261,7 +266,7 @@ describe('NfRegistry Service isolated unit tests', function () { //assertions expect(allSelected).toBe(true); - expect(nfRegistryService.disableMultiBucketActions).toBe(false); + expect(nfRegistryService.isMultiBucketActionsDisabled).toBe(false); }); it('should set the `allBucketsSelected` state to true.', function () { @@ -324,7 +329,7 @@ describe('NfRegistry Service isolated unit tests', function () { //assertions expect(nfRegistryService.filteredBuckets[0].checked).toBe(true); - expect(nfRegistryService.disableMultiBucketActions).toBe(false); + expect(nfRegistryService.isMultiBucketActionsDisabled).toBe(false); }); it('should deselect all buckets.', function () { @@ -335,7 +340,7 @@ describe('NfRegistry Service isolated unit tests', function () { //assertions expect(nfRegistryService.filteredBuckets[0].checked).toBe(false); - expect(nfRegistryService.disableMultiBucketActions).toBe(true); + expect(nfRegistryService.isMultiBucketActionsDisabled).toBe(true); }); it('should add a bucket search term.', function () { @@ -373,6 +378,7 @@ describe('NfRegistry Service w/ Angular testing utils', function () { var comp; var fixture; var nfRegistryService; + var nfRegistryApi; beforeEach(function () { ngCoreTesting.TestBed.configureTestingModule({ @@ -380,8 +386,10 @@ describe('NfRegistry Service w/ Angular testing utils', function () { ngMoment.MomentModule, ngHttp.HttpModule, ngHttp.JsonpModule, + ngCommonHttp.HttpClientModule, fdsCore, - NfRegistryRoutes + NfRegistryRoutes, + ngCommonHttpTesting.HttpClientTestingModule ], declarations: [ FdsDemo, @@ -391,6 +399,7 @@ describe('NfRegistry Service w/ Angular testing utils', function () { NfRegistryUsersAdministration, NfRegistryUserDetails, NfRegistryUserPermissions, + NfRegistryUserGroupPermissions, NfRegistryBucketPermissions, NfRegistryAddUser, NfRegistryWorkflowAdministration, @@ -401,7 +410,14 @@ describe('NfRegistry Service w/ Angular testing utils', function () { ], providers: [ NfRegistryService, + NfRegistryAuthService, NfRegistryApi, + NfStorage, + { + provide: ngCommonHttp.HTTP_INTERCEPTORS, + useClass: NfRegistryTokenInterceptor, + multi: true + }, { provide: ngCommon.APP_BASE_HREF, useValue: '/' @@ -426,12 +442,15 @@ describe('NfRegistry Service w/ Angular testing utils', function () { fixture.detectChanges(); // Spy - spyOn(nfRegistryApi.http, 'get').and.callThrough(); + spyOn(nfRegistryApi.http, 'get').and.callFake(function () {}); + spyOn(nfRegistryApi.http, 'post').and.callFake(function () {}); + spyOn(nfRegistryApi, 'ticketExchange').and.callFake(function () {}).and.returnValue(rxjs.Observable.of({})); + spyOn(nfRegistryService, 'loadCurrentUser').and.callFake(function () {}).and.returnValue(rxjs.Observable.of({})); }); it('should retrieve the snapshot metadata for the given droplet.', ngCoreTesting.fakeAsync(function () { //Spy - spyOn(nfRegistryService.api, 'getDropletSnapshotMetadata').and.callFake(function () { + spyOn(nfRegistryApi, 'getDropletSnapshotMetadata').and.callFake(function () { }).and.returnValue(rxjs.Observable.of([{ version: 999 }])); @@ -450,9 +469,9 @@ describe('NfRegistry Service w/ Angular testing utils', function () { //assertions expect(droplet.snapshotMetadata[0].version).toBe(999); - expect(nfRegistryService.api.getDropletSnapshotMetadata).toHaveBeenCalled(); - expect(nfRegistryService.api.getDropletSnapshotMetadata.calls.count()).toBe(1); - var getDropletSnapshotMetadataCall = nfRegistryService.api.getDropletSnapshotMetadata.calls.first() + expect(nfRegistryApi.getDropletSnapshotMetadata).toHaveBeenCalled(); + expect(nfRegistryApi.getDropletSnapshotMetadata.calls.count()).toBe(1); + var getDropletSnapshotMetadataCall = nfRegistryApi.getDropletSnapshotMetadata.calls.first() expect(getDropletSnapshotMetadataCall.args[0]).toBe('test/id'); expect(getDropletSnapshotMetadataCall.args[1]).toBe(true); })); @@ -467,7 +486,7 @@ describe('NfRegistry Service w/ Angular testing utils', function () { return rxjs.Observable.of(true); } }); - spyOn(nfRegistryService.api, 'deleteDroplet').and.callFake(function () { + spyOn(nfRegistryApi, 'deleteDroplet').and.callFake(function () { }).and.returnValue(rxjs.Observable.of({identifier: '2e04b4fb-9513-47bb-aa74-1ae34616bfdc', link: null})); spyOn(nfRegistryService, 'filterDroplets').and.callFake(function () { }); @@ -479,7 +498,7 @@ describe('NfRegistry Service w/ Angular testing utils', function () { link: {href: 'testhref'} }); - // wait for async nfRegistryService.api.deleteDroplet call + // wait for async nfRegistryApi.deleteDroplet call ngCoreTesting.tick(); //inform angular to detect changes @@ -490,7 +509,7 @@ describe('NfRegistry Service w/ Angular testing utils', function () { expect(nfRegistryService.filterDroplets).toHaveBeenCalled(); var openConfirmCall = nfRegistryService.dialogService.openConfirm.calls.first() expect(openConfirmCall.args[0].title).toBe('Delete testtype'); - var deleteDropletCall = nfRegistryService.api.deleteDroplet.calls.first() + var deleteDropletCall = nfRegistryApi.deleteDroplet.calls.first() expect(deleteDropletCall.args[0]).toBe('testhref'); })); @@ -535,7 +554,7 @@ describe('NfRegistry Service w/ Angular testing utils', function () { // The function to test nfRegistryService.filterDroplets(); - // wait for async nfRegistryService.api.deleteDroplet call + // wait for async nfRegistryApi.deleteDroplet call ngCoreTesting.tick(); //inform angular to detect changes @@ -588,7 +607,7 @@ describe('NfRegistry Service w/ Angular testing utils', function () { // The function to test nfRegistryService.filterDroplets(); - // wait for async nfRegistryService.api.deleteDroplet call + // wait for async nfRegistryApi.deleteDroplet call ngCoreTesting.tick(); //inform angular to detect changes @@ -613,7 +632,7 @@ describe('NfRegistry Service w/ Angular testing utils', function () { return rxjs.Observable.of(true); } }); - spyOn(nfRegistryService.api, 'deleteBucket').and.callFake(function () { + spyOn(nfRegistryApi, 'deleteBucket').and.callFake(function () { }).and.returnValue(rxjs.Observable.of({identifier: '2e04b4fb-9513-47bb-aa74-1ae34616bfdc', link: null})); // object to be updated by the test @@ -639,7 +658,7 @@ describe('NfRegistry Service w/ Angular testing utils', function () { //assertions expect(dialogService.openConfirm).toHaveBeenCalled(); - expect(nfRegistryService.api.deleteBucket).toHaveBeenCalled(); + expect(nfRegistryApi.deleteBucket).toHaveBeenCalled(); expect(nfRegistryService.filterBuckets).toHaveBeenCalled(); expect(nfRegistryService.buckets.length).toBe(1); expect(nfRegistryService.buckets[0].identifier).toBe(1); @@ -683,12 +702,12 @@ describe('NfRegistry Service w/ Angular testing utils', function () { spyOn(nfRegistryService, 'getAutoCompleteBuckets'); //assertion - expect(nfRegistryService.disableMultiBucketActions).toBe(true); + expect(nfRegistryService.isMultiBucketActionsDisabled).toBe(true); // The function to test nfRegistryService.filterBuckets(); - // wait for async nfRegistryService.api.deleteDroplet call + // wait for async nfRegistryApi.deleteDroplet call ngCoreTesting.tick(); //inform angular to detect changes @@ -698,7 +717,7 @@ describe('NfRegistry Service w/ Angular testing utils', function () { expect(nfRegistryService.filteredBuckets.length).toBe(1); expect(nfRegistryService.filteredBuckets[0].name).toBe('Bucket #1'); expect(nfRegistryService.getAutoCompleteBuckets).toHaveBeenCalled(); - expect(nfRegistryService.disableMultiBucketActions).toBe(false); + expect(nfRegistryService.isMultiBucketActionsDisabled).toBe(false); })); it('should delete all selected buckets.', ngCoreTesting.fakeAsync(function () { @@ -716,7 +735,7 @@ describe('NfRegistry Service w/ Angular testing utils', function () { return rxjs.Observable.of(true); } }); - spyOn(nfRegistryService.api, 'deleteBucket').and.callFake(function () { + spyOn(nfRegistryApi, 'deleteBucket').and.callFake(function () { }).and.returnValue(rxjs.Observable.of({identifier: 999, link: null})); // object to be updated by the test @@ -742,11 +761,11 @@ describe('NfRegistry Service w/ Angular testing utils', function () { //assertions expect(dialogService.openConfirm).toHaveBeenCalled(); - expect(nfRegistryService.api.deleteBucket).toHaveBeenCalled(); - expect(nfRegistryService.api.deleteBucket.calls.count()).toBe(1); + expect(nfRegistryApi.deleteBucket).toHaveBeenCalled(); + expect(nfRegistryApi.deleteBucket.calls.count()).toBe(1); expect(nfRegistryService.filterBuckets).toHaveBeenCalled(); expect(nfRegistryService.filterBuckets.calls.count()).toBe(1); - expect(nfRegistryService.disableMultiBucketActions).toBe(true); + expect(nfRegistryService.isMultiBucketActionsDisabled).toBe(true); expect(nfRegistryService.allBucketsSelected).toBe(false); expect(nfRegistryService.buckets.length).toBe(1); expect(nfRegistryService.buckets[0].identifier).toBe(1); http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/247985ad/nifi-registry-web-ui/src/main/webapp/services/nf-registry.token.interceptor.js ---------------------------------------------------------------------- diff --git a/nifi-registry-web-ui/src/main/webapp/services/nf-registry.token.interceptor.js b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.token.interceptor.js new file mode 100644 index 0000000..e1abb95 --- /dev/null +++ b/nifi-registry-web-ui/src/main/webapp/services/nf-registry.token.interceptor.js @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +var NfRegistryAuthService = require('nifi-registry/services/nf-registry.auth.service.js'); + +/** + * NfRegistryTokenInterceptor constructor. + * @constructor + */ +function NfRegistryTokenInterceptor(nfRegistryAuthService) { + this.auth = nfRegistryAuthService; +}; + +NfRegistryTokenInterceptor.prototype = { + constructor: NfRegistryTokenInterceptor, + + /** + * Generates the droplet grid-list explorer component's sorting menu options. + * + * @param request angular HttpRequest. + * @param next angular HttpHandler. + * @returns {Observable HTTPEvent} + */ + intercept: function(request, next) { + var token = this.auth.getToken(); + if(token) { + request = request.clone({headers: request.headers.set('Authorization', 'Bearer ' + token)}); + } + return next.handle(request); + } +}; + +NfRegistryTokenInterceptor.parameters = [NfRegistryAuthService]; + +module.exports = NfRegistryTokenInterceptor; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/247985ad/nifi-registry-web-ui/src/main/webapp/services/nf-storage.service.js ---------------------------------------------------------------------- diff --git a/nifi-registry-web-ui/src/main/webapp/services/nf-storage.service.js b/nifi-registry-web-ui/src/main/webapp/services/nf-storage.service.js new file mode 100644 index 0000000..f1045b9 --- /dev/null +++ b/nifi-registry-web-ui/src/main/webapp/services/nf-storage.service.js @@ -0,0 +1,219 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +// Store items for two days before being eligible for removal. +var MILLIS_PER_DAY = 86400000; +var TWO_DAYS = MILLIS_PER_DAY * 2; + +var isUndefined = function (obj) { + return typeof obj === 'undefined'; +}; + +var isNull = function (obj) { + return obj === null; +}; + +var isDefinedAndNotNull = function (obj) { + return !isUndefined(obj) && !isNull(obj); +}; + +/** + * Checks the expiration for the specified entry. + * + * @param {object} entry + * @returns {boolean} + */ +var checkExpiration = function (entry) { + if (isDefinedAndNotNull(entry.expires)) { + // get the expiration + var expires = new Date(entry.expires); + var now = new Date(); + + // return whether the expiration date has passed + return expires.valueOf() < now.valueOf(); + } else { + return false; + } +}; + +/** + * Gets an enty for the key. The entry expiration is not checked. + * + * @param {string} key + */ +var getEntry = function (key) { + try { + // parse the entry + var entry = JSON.parse(localStorage.getItem(key)); + + // ensure the entry and item are present + if (isDefinedAndNotNull(entry)) { + return entry; + } else { + return null; + } + } catch (e) { + return null; + } +}; + +/** + * NfRegistryStorage constructor. + * @constructor + */ +function NfRegistryStorage() { +}; + +NfRegistryStorage.prototype = { + constructor: NfRegistryStorage, + /** + * Initializes the storage. Items will be persisted for two days. Once the scripts runs + * thereafter, all eligible items will be removed. This strategy does not support persistence. + */ + init: function () { + for (var i = 0; i < localStorage.length; i++) { + try { + // get the next item + var key = localStorage.key(i); + + // attempt to get the item which will expire if necessary + this.getItem(key); + } catch (e) { + } + } + }, + + /** + * Stores the specified item. + * + * @param {string} key + * @param {object} item + * @param {integer} expires + */ + setItem: function (key, item, expires) { + // calculate the expiration + expires = isDefinedAndNotNull(expires) ? expires : new Date().valueOf() + TWO_DAYS; + + // create the entry + var entry = { + expires: expires, + item: item + }; + + // store the item + localStorage.setItem(key, JSON.stringify(entry)); + }, + + /** + * Returns whether there is an entry for this key. This will not check the expiration. If + * the entry is expired, it will return null on a subsequent getItem invocation. + * + * @param {string} key + * @returns {boolean} + */ + hasItem: function (key) { + return getEntry(key) !== null; + }, + + /** + * Gets the item with the specified key. If an item with this key does + * not exist, null is returned. If an item exists but cannot be parsed + * or is malformed/unrecognized, null is returned. + * + * @param {type} key + */ + getItem: function (key) { + var entry = getEntry(key); + if (entry === null) { + return null; + } + + // if the entry is expired, drop it and return null + if (checkExpiration(entry)) { + this.removeItem(key); + return null; + } + + // if the entry has the specified field return its value + if (isDefinedAndNotNull(entry['item'])) { + return entry['item']; + } else { + return null; + } + }, + + /** + * Gets the expiration for the specified item. This will not check the expiration. If + * the entry is expired, it will return null on a subsequent getItem invocation. + * + * @param {string} key + * @returns {integer} + */ + getItemExpiration: function (key) { + var entry = getEntry(key); + if (entry === null) { + return null; + } + + // if the entry has the specified field return its value + if (isDefinedAndNotNull(entry['expires'])) { + return entry['expires']; + } else { + return null; + } + }, + + /** + * Extracts the subject from the specified jwt. If the jwt is not as expected + * an empty string is returned. + * + * @param {string} jwt + * @returns {string} + */ + getJwtPayload: function (jwt) { + if (isDefinedAndNotNull(jwt)) { + var segments = jwt.split(/\./); + if (segments.length !== 3) { + return ''; + } + + var rawPayload = window.atob(segments[1]); + var payload = JSON.parse(rawPayload); + + if (isDefinedAndNotNull(payload)) { + return payload; + } else { + return null; + } + } + + return null; + }, + + /** + * Removes the item with the specified key. + * + * @param {type} key + */ + removeItem: function (key) { + localStorage.removeItem(key); + } +}; + +NfRegistryStorage.parameters = []; + +module.exports = NfRegistryStorage; \ No newline at end of file http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/247985ad/nifi-registry-web-ui/src/main/webapp/systemjs.builder.config.js ---------------------------------------------------------------------- diff --git a/nifi-registry-web-ui/src/main/webapp/systemjs.builder.config.js b/nifi-registry-web-ui/src/main/webapp/systemjs.builder.config.js index a32bb3e..fa874e2 100644 --- a/nifi-registry-web-ui/src/main/webapp/systemjs.builder.config.js +++ b/nifi-registry-web-ui/src/main/webapp/systemjs.builder.config.js @@ -33,6 +33,7 @@ // Angular '@angular/core': 'npm:@angular/core/bundles/core.umd.js', '@angular/common': 'npm:@angular/common/bundles/common.umd.js', + '@angular/common/http': 'npm:@angular/common/bundles/common-http.umd.js', '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', '@angular/http': 'npm:@angular/http/bundles/http.umd.js', @@ -74,6 +75,7 @@ 'core-js': 'npm:core-js/client/shim.min.js', 'superagent': 'npm:superagent/superagent.js', 'querystring': 'npm:querystring', + 'tslib': 'npm:tslib/tslib.js', // Fluid Design System '@fluid-design-system/core': 'npm:@fluid-design-system/dist/platform/core/fluid-design-system.module.js', @@ -94,13 +96,19 @@ 'nifi-registry/nf-registry.js': 'nf-registry.js', 'nifi-registry/services/nf-registry.api.js': 'services/nf-registry.api.js', 'nifi-registry/services/nf-registry.service.js': 'services/nf-registry.service.js', + 'nifi-registry/services/nf-storage.service.js': 'services/nf-storage.service.js', + 'nifi-registry/services/nf-registry.auth.service.js': 'services/nf-registry.auth.service.js', + 'nifi-registry/services/nf-registry.token.interceptor.js': 'services/nf-registry.token.interceptor.js', 'nifi-registry/components/page-not-found/nf-registry-page-not-found.js': 'components/page-not-found/nf-registry-page-not-found.js', 'nifi-registry/components/explorer/nf-registry-explorer.js': 'components/explorer/nf-registry-explorer.js', 'nifi-registry/components/administration/nf-registry-administration.js': 'components/administration/nf-registry-administration.js', 'nifi-registry/components/administration/users/nf-registry-users-administration.js': 'components/administration/users/nf-registry-users-administration.js', - 'nifi-registry/components/administration/users/add/nf-registry-add-user.js': 'components/administration/users/add/nf-registry-add-user.js', + 'nifi-registry/components/administration/users/dialogs/add-user/nf-registry-add-user.js': 'components/administration/users/dialogs/add-user/nf-registry-add-user.js', + 'nifi-registry/components/administration/users/dialogs/create-new-group/nf-registry-create-new-group.js': 'components/administration/users/dialogs/create-new-group/nf-registry-create-new-group.js', + 'nifi-registry/components/administration/users/dialogs/add-selected-users-to-group/nf-registry-add-selected-users-to-group.js': 'components/administration/users/dialogs/add-selected-users-to-group/nf-registry-add-selected-users-to-group.js', 'nifi-registry/components/administration/users/details/nf-registry-user-details.js': 'components/administration/users/details/nf-registry-user-details.js', 'nifi-registry/components/administration/users/permissions/nf-registry-user-permissions.js': 'components/administration/users/permissions/nf-registry-user-permissions.js', + 'nifi-registry/components/administration/user-group/permissions/nf-registry-user-group-permissions.js': 'components/administration/user-group/permissions/nf-registry-user-group-permissions.js', 'nifi-registry/components/administration/workflow/dialogs/nf-registry-create-bucket.js': 'components/administration/workflow/dialogs/nf-registry-create-bucket.js', 'nifi-registry/components/administration/workflow/buckets/permissions/nf-registry-bucket-permissions.js': 'components/administration/workflow/buckets/permissions/nf-registry-bucket-permissions.js', 'nifi-registry/components/administration/workflow/nf-registry-workflow-administration.js': 'components/administration/workflow/nf-registry-workflow-administration.js', http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/247985ad/nifi-registry-web-ui/src/main/webapp/systemjs.spec.config.js ---------------------------------------------------------------------- diff --git a/nifi-registry-web-ui/src/main/webapp/systemjs.spec.config.js b/nifi-registry-web-ui/src/main/webapp/systemjs.spec.config.js index fd40882..fead0bc 100644 --- a/nifi-registry-web-ui/src/main/webapp/systemjs.spec.config.js +++ b/nifi-registry-web-ui/src/main/webapp/systemjs.spec.config.js @@ -32,6 +32,8 @@ // Angular '@angular/core': 'npm:@angular/core/bundles/core.umd.js', '@angular/common': 'npm:@angular/common/bundles/common.umd.js', + '@angular/common/http': 'npm:@angular/common/bundles/common-http.umd.js', + '@angular/common/http/testing': 'npm:@angular/common/bundles/common-http-testing.umd.js', '@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js', '@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js', '@angular/http': 'npm:@angular/http/bundles/http.umd.js', @@ -73,6 +75,7 @@ 'core-js': 'npm:core-js/client/shim.min.js', 'superagent': 'npm:superagent/superagent.js', 'querystring': 'npm:querystring', + 'tslib': 'npm:tslib/tslib.js', // Fluid Design System '@fluid-design-system/core': 'npm:@fluid-design-system/dist/platform/core/fluid-design-system.module.js', http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/247985ad/nifi-registry-web-ui/src/main/webapp/theming/_structureElements.scss ---------------------------------------------------------------------- diff --git a/nifi-registry-web-ui/src/main/webapp/theming/_structureElements.scss b/nifi-registry-web-ui/src/main/webapp/theming/_structureElements.scss index 5e9a1c2..b8f8978 100644 --- a/nifi-registry-web-ui/src/main/webapp/theming/_structureElements.scss +++ b/nifi-registry-web-ui/src/main/webapp/theming/_structureElements.scss @@ -16,7 +16,8 @@ */ body { - background: $grey5; + background: $grey5 url('/nifi-registry/images/registry-logo-web-app.svg') no-repeat center center; + background-size: 40%; } #nf-registry-app-container { @@ -70,10 +71,35 @@ body { left: 0px; right: 0px; bottom: 0px; - background: $grey5; min-height: 370px; min-width: 1045px; overflow: auto; + background: $grey5 url('/nifi-registry/images/registry-logo-web-app.svg') no-repeat center center; + background-size: 40%; +} + +#current-user { + font-family: 'Roboto Slab'; + font-style: normal; + font-weight: normal; + font-size: 12px; + max-width: 250px; + text-overflow: ellipsis; + line-height: normal; + overflow: hidden; + white-space: nowrap; + color: $grey5; +} + +#logout-link-container { + font-size: 12px; + text-transform:uppercase; +} + +#loading-spinner { + position: absolute; + top: calc(50% - 50px); + left: calc(50% - 50px); } mat-sidenav { http://git-wip-us.apache.org/repos/asf/nifi-registry/blob/247985ad/nifi-registry-web-ui/src/main/webapp/theming/components/administration/users/_structureElements.scss ---------------------------------------------------------------------- diff --git a/nifi-registry-web-ui/src/main/webapp/theming/components/administration/users/_structureElements.scss b/nifi-registry-web-ui/src/main/webapp/theming/components/administration/users/_structureElements.scss index 0c41820..0d5c4ad 100644 --- a/nifi-registry-web-ui/src/main/webapp/theming/components/administration/users/_structureElements.scss +++ b/nifi-registry-web-ui/src/main/webapp/theming/components/administration/users/_structureElements.scss @@ -47,7 +47,7 @@ right: 10px; } -#nf-registry-add-user-side-nav-container { +#nf-registry-user-group-permissions-side-nav-container { position: absolute; bottom: 15px; right: 10px; @@ -59,3 +59,8 @@ right: 10px; } +#nifi-registry-add-selected-users-to-group-list-container { + width: 100%; + overflow: auto; + max-height: 245px; +}
