1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-12-25 16:59:17 +01:00

rename subvault => collection

This commit is contained in:
Kyle Spearrin 2017-04-27 09:33:12 -04:00
parent 361f03eb5f
commit 1ebae5c284
37 changed files with 555 additions and 555 deletions

View File

@ -82,11 +82,11 @@ angular
refreshFromServer: false refreshFromServer: false
} }
}) })
.state('backend.user.subvaults', { .state('backend.user.collections', {
url: '^/subvaults', url: '^/collections',
templateUrl: 'app/vault/views/vaultSubvaults.html', templateUrl: 'app/vault/views/vaultCollections.html',
controller: 'vaultSubvaultsController', controller: 'vaultCollectionsController',
data: { pageTitle: 'Subvaults' } data: { pageTitle: 'Collections' }
}) })
.state('backend.user.settings', { .state('backend.user.settings', {
url: '^/settings', url: '^/settings',
@ -134,11 +134,11 @@ angular
controller: 'organizationPeopleController', controller: 'organizationPeopleController',
data: { pageTitle: 'Organization People' } data: { pageTitle: 'Organization People' }
}) })
.state('backend.org.subvaults', { .state('backend.org.collections', {
url: '/organization/:orgId/subvaults', url: '/organization/:orgId/collections',
templateUrl: 'app/organization/views/organizationSubvaults.html', templateUrl: 'app/organization/views/organizationCollections.html',
controller: 'organizationSubvaultsController', controller: 'organizationCollectionsController',
data: { pageTitle: 'Organization Subvaults' } data: { pageTitle: 'Organization Collections' }
}) })
.state('backend.org.settings', { .state('backend.org.settings', {
url: '/organization/:orgId/settings', url: '/organization/:orgId/settings',

View File

@ -94,7 +94,7 @@
email: list.Data[i].Email, email: list.Data[i].Email,
status: list.Data[i].Status, status: list.Data[i].Status,
type: list.Data[i].Type, type: list.Data[i].Type,
accessAllSubvaults: list.Data[i].AccessAllSubvaults accessAllCollections: list.Data[i].AccessAllCollections
}; };
users.push(user); users.push(user);

View File

@ -6,88 +6,88 @@
$analytics.eventTrack('organizationPeopleEditController', { category: 'Modal' }); $analytics.eventTrack('organizationPeopleEditController', { category: 'Modal' });
$scope.loading = true; $scope.loading = true;
$scope.subvaults = []; $scope.collections = [];
$scope.selectedSubvaults = {}; $scope.selectedCollections = {};
$uibModalInstance.opened.then(function () { $uibModalInstance.opened.then(function () {
apiService.subvaults.listOrganization({ orgId: $state.params.orgId }, function (list) { apiService.collections.listOrganization({ orgId: $state.params.orgId }, function (list) {
$scope.subvaults = cipherService.decryptSubvaults(list.Data, $state.params.orgId, true); $scope.collections = cipherService.decryptCollections(list.Data, $state.params.orgId, true);
$scope.loading = false; $scope.loading = false;
}); });
apiService.organizationUsers.get({ orgId: $state.params.orgId, id: id }, function (user) { apiService.organizationUsers.get({ orgId: $state.params.orgId, id: id }, function (user) {
var subvaults = {}; var collections = {};
if (user && user.Subvaults) { if (user && user.Collections) {
for (var i = 0; i < user.Subvaults.Data.length; i++) { for (var i = 0; i < user.Collections.Data.length; i++) {
subvaults[user.Subvaults.Data[i].SubvaultId] = { collections[user.Collections.Data[i].CollectionId] = {
subvaultId: user.Subvaults.Data[i].SubvaultId, collectionId: user.Collections.Data[i].CollectionId,
readOnly: user.Subvaults.Data[i].ReadOnly readOnly: user.Collections.Data[i].ReadOnly
}; };
} }
} }
$scope.email = user.Email; $scope.email = user.Email;
$scope.type = user.Type; $scope.type = user.Type;
$scope.accessAllSubvaults = user.AccessAllSubvaults; $scope.accessAllCollections = user.AccessAllCollections;
$scope.selectedSubvaults = subvaults; $scope.selectedCollections = collections;
}); });
}); });
$scope.toggleSubvaultSelectionAll = function ($event) { $scope.toggleCollectionSelectionAll = function ($event) {
var subvaults = {}; var collections = {};
if ($event.target.checked) { if ($event.target.checked) {
for (var i = 0; i < $scope.subvaults.length; i++) { for (var i = 0; i < $scope.collections.length; i++) {
subvaults[$scope.subvaults[i].id] = { collections[$scope.collections[i].id] = {
subvaultId: $scope.subvaults[i].id, collectionId: $scope.collections[i].id,
readOnly: ($scope.subvaults[i].id in $scope.selectedSubvaults) ? readOnly: ($scope.collections[i].id in $scope.selectedCollections) ?
$scope.selectedSubvaults[$scope.subvaults[i].id].readOnly : false $scope.selectedCollections[$scope.collections[i].id].readOnly : false
}; };
} }
} }
$scope.selectedSubvaults = subvaults; $scope.selectedCollections = collections;
}; };
$scope.toggleSubvaultSelection = function (id) { $scope.toggleCollectionSelection = function (id) {
if (id in $scope.selectedSubvaults) { if (id in $scope.selectedCollections) {
delete $scope.selectedSubvaults[id]; delete $scope.selectedCollections[id];
} }
else { else {
$scope.selectedSubvaults[id] = { $scope.selectedCollections[id] = {
subvaultId: id, collectionId: id,
readOnly: false readOnly: false
}; };
} }
}; };
$scope.toggleSubvaultReadOnlySelection = function (id) { $scope.toggleCollectionReadOnlySelection = function (id) {
if (id in $scope.selectedSubvaults) { if (id in $scope.selectedCollections) {
$scope.selectedSubvaults[id].readOnly = !!!$scope.selectedSubvaults[id].readOnly; $scope.selectedCollections[id].readOnly = !!!$scope.selectedCollections[id].readOnly;
} }
}; };
$scope.subvaultSelected = function (subvault) { $scope.collectionSelected = function (collection) {
return subvault.id in $scope.selectedSubvaults; return collection.id in $scope.selectedCollections;
}; };
$scope.allSelected = function () { $scope.allSelected = function () {
return Object.keys($scope.selectedSubvaults).length === $scope.subvaults.length; return Object.keys($scope.selectedCollections).length === $scope.collections.length;
}; };
$scope.submitPromise = null; $scope.submitPromise = null;
$scope.submit = function (model) { $scope.submit = function (model) {
var subvaults = []; var collections = [];
if (!$scope.accessAllSubvaults) { if (!$scope.accessAllCollections) {
for (var subvaultId in $scope.selectedSubvaults) { for (var collectionId in $scope.selectedCollections) {
if ($scope.selectedSubvaults.hasOwnProperty(subvaultId)) { if ($scope.selectedCollections.hasOwnProperty(collectionId)) {
subvaults.push($scope.selectedSubvaults[subvaultId]); collections.push($scope.selectedCollections[collectionId]);
} }
} }
} }
$scope.submitPromise = apiService.organizationUsers.put({ orgId: $state.params.orgId, id: id }, { $scope.submitPromise = apiService.organizationUsers.put({ orgId: $state.params.orgId, id: id }, {
type: $scope.type, type: $scope.type,
subvaults: subvaults, collections: collections,
accessAllSubvaults: $scope.accessAllSubvaults accessAllCollections: $scope.accessAllCollections
}, function () { }, function () {
$analytics.eventTrack('Edited User'); $analytics.eventTrack('Edited User');
$uibModalInstance.close(); $uibModalInstance.close();

View File

@ -6,68 +6,68 @@
$analytics.eventTrack('organizationPeopleInviteController', { category: 'Modal' }); $analytics.eventTrack('organizationPeopleInviteController', { category: 'Modal' });
$scope.loading = true; $scope.loading = true;
$scope.subvaults = []; $scope.collections = [];
$scope.selectedSubvaults = {}; $scope.selectedCollections = {};
$scope.model = { $scope.model = {
type: 'User' type: 'User'
}; };
$uibModalInstance.opened.then(function () { $uibModalInstance.opened.then(function () {
apiService.subvaults.listOrganization({ orgId: $state.params.orgId }, function (list) { apiService.collections.listOrganization({ orgId: $state.params.orgId }, function (list) {
$scope.subvaults = cipherService.decryptSubvaults(list.Data, $state.params.orgId, true); $scope.collections = cipherService.decryptCollections(list.Data, $state.params.orgId, true);
$scope.loading = false; $scope.loading = false;
}); });
}); });
$scope.toggleSubvaultSelectionAll = function ($event) { $scope.toggleCollectionSelectionAll = function ($event) {
var subvaults = {}; var collections = {};
if ($event.target.checked) { if ($event.target.checked) {
for (var i = 0; i < $scope.subvaults.length; i++) { for (var i = 0; i < $scope.collections.length; i++) {
subvaults[$scope.subvaults[i].id] = { collections[$scope.collections[i].id] = {
subvaultId: $scope.subvaults[i].id, collectionId: $scope.collections[i].id,
readOnly: ($scope.subvaults[i].id in $scope.selectedSubvaults) ? readOnly: ($scope.collections[i].id in $scope.selectedCollections) ?
$scope.selectedSubvaults[$scope.subvaults[i].id].readOnly : false $scope.selectedCollections[$scope.collections[i].id].readOnly : false
}; };
} }
} }
$scope.selectedSubvaults = subvaults; $scope.selectedCollections = collections;
}; };
$scope.toggleSubvaultSelection = function (id) { $scope.toggleCollectionSelection = function (id) {
if (id in $scope.selectedSubvaults) { if (id in $scope.selectedCollections) {
delete $scope.selectedSubvaults[id]; delete $scope.selectedCollections[id];
} }
else { else {
$scope.selectedSubvaults[id] = { $scope.selectedCollections[id] = {
subvaultId: id, collectionId: id,
readOnly: false readOnly: false
}; };
} }
}; };
$scope.toggleSubvaultReadOnlySelection = function (id) { $scope.toggleCollectionReadOnlySelection = function (id) {
if (id in $scope.selectedSubvaults) { if (id in $scope.selectedCollections) {
$scope.selectedSubvaults[id].readOnly = !!!$scope.selectedSubvaults[id].readOnly; $scope.selectedCollections[id].readOnly = !!!$scope.selectedCollections[id].readOnly;
} }
}; };
$scope.subvaultSelected = function (subvault) { $scope.collectionSelected = function (collection) {
return subvault.id in $scope.selectedSubvaults; return collection.id in $scope.selectedCollections;
}; };
$scope.allSelected = function () { $scope.allSelected = function () {
return Object.keys($scope.selectedSubvaults).length === $scope.subvaults.length; return Object.keys($scope.selectedCollections).length === $scope.collections.length;
}; };
$scope.submitPromise = null; $scope.submitPromise = null;
$scope.submit = function (model) { $scope.submit = function (model) {
var subvaults = []; var collections = [];
if (!model.accessAllSubvaults) { if (!model.accessAllCollections) {
for (var subvaultId in $scope.selectedSubvaults) { for (var collectionId in $scope.selectedCollections) {
if ($scope.selectedSubvaults.hasOwnProperty(subvaultId)) { if ($scope.selectedCollections.hasOwnProperty(collectionId)) {
subvaults.push($scope.selectedSubvaults[subvaultId]); collections.push($scope.selectedCollections[collectionId]);
} }
} }
} }
@ -75,8 +75,8 @@
$scope.submitPromise = apiService.organizationUsers.invite({ orgId: $state.params.orgId }, { $scope.submitPromise = apiService.organizationUsers.invite({ orgId: $state.params.orgId }, {
email: model.email, email: model.email,
type: model.type, type: model.type,
subvaults: subvaults, collections: collections,
accessAllSubvaults: model.accessAllSubvaults accessAllCollections: model.accessAllCollections
}, function () { }, function () {
$analytics.eventTrack('Invited User'); $analytics.eventTrack('Invited User');
$uibModalInstance.close(); $uibModalInstance.close();

View File

@ -1,16 +1,16 @@
angular angular
.module('bit.organization') .module('bit.organization')
.controller('organizationSubvaultsAddController', function ($scope, $state, $uibModalInstance, apiService, cipherService, .controller('organizationCollectionsAddController', function ($scope, $state, $uibModalInstance, apiService, cipherService,
$analytics) { $analytics) {
$analytics.eventTrack('organizationSubvaultsAddController', { category: 'Modal' }); $analytics.eventTrack('organizationCollectionsAddController', { category: 'Modal' });
$scope.submit = function (model) { $scope.submit = function (model) {
var subvault = cipherService.encryptSubvault(model, $state.params.orgId); var collection = cipherService.encryptCollection(model, $state.params.orgId);
$scope.submitPromise = apiService.subvaults.post({ orgId: $state.params.orgId }, subvault, function (response) { $scope.submitPromise = apiService.collections.post({ orgId: $state.params.orgId }, collection, function (response) {
$analytics.eventTrack('Created Subvault'); $analytics.eventTrack('Created Collection');
var decSubvault = cipherService.decryptSubvault(response, $state.params.orgId, true); var decCollection = cipherService.decryptCollection(response, $state.params.orgId, true);
$uibModalInstance.close(decSubvault); $uibModalInstance.close(decCollection);
}).$promise; }).$promise;
}; };

View File

@ -1,9 +1,9 @@
angular angular
.module('bit.organization') .module('bit.organization')
.controller('organizationSubvaultsController', function ($scope, $state, apiService, $uibModal, cipherService, $filter, .controller('organizationCollectionsController', function ($scope, $state, apiService, $uibModal, cipherService, $filter,
toastr, $analytics) { toastr, $analytics) {
$scope.subvaults = []; $scope.collections = [];
$scope.loading = true; $scope.loading = true;
$scope.$on('$viewContentLoaded', function () { $scope.$on('$viewContentLoaded', function () {
loadList(); loadList();
@ -12,41 +12,41 @@
$scope.add = function () { $scope.add = function () {
var modal = $uibModal.open({ var modal = $uibModal.open({
animation: true, animation: true,
templateUrl: 'app/organization/views/organizationSubvaultsAdd.html', templateUrl: 'app/organization/views/organizationCollectionsAdd.html',
controller: 'organizationSubvaultsAddController' controller: 'organizationCollectionsAddController'
}); });
modal.result.then(function (subvault) { modal.result.then(function (collection) {
$scope.subvaults.push(subvault); $scope.collections.push(collection);
}); });
}; };
$scope.edit = function (subvault) { $scope.edit = function (collection) {
var modal = $uibModal.open({ var modal = $uibModal.open({
animation: true, animation: true,
templateUrl: 'app/organization/views/organizationSubvaultsEdit.html', templateUrl: 'app/organization/views/organizationCollectionsEdit.html',
controller: 'organizationSubvaultsEditController', controller: 'organizationCollectionsEditController',
resolve: { resolve: {
id: function () { return subvault.id; } id: function () { return collection.id; }
} }
}); });
modal.result.then(function (editedSubvault) { modal.result.then(function (editedCollection) {
var existingSubvaults = $filter('filter')($scope.subvaults, { id: editedSubvault.id }, true); var existingCollections = $filter('filter')($scope.collections, { id: editedCollection.id }, true);
if (existingSubvaults && existingSubvaults.length > 0) { if (existingCollections && existingCollections.length > 0) {
existingSubvaults[0].name = editedSubvault.name; existingCollections[0].name = editedCollection.name;
} }
}); });
}; };
$scope.users = function (subvault) { $scope.users = function (collection) {
var modal = $uibModal.open({ var modal = $uibModal.open({
animation: true, animation: true,
templateUrl: 'app/organization/views/organizationSubvaultsUsers.html', templateUrl: 'app/organization/views/organizationCollectionsUsers.html',
controller: 'organizationSubvaultsUsersController', controller: 'organizationCollectionsUsersController',
size: 'lg', size: 'lg',
resolve: { resolve: {
subvault: function () { return subvault; } collection: function () { return collection; }
} }
}); });
@ -55,13 +55,13 @@
}); });
}; };
$scope.groups = function (subvault) { $scope.groups = function (collection) {
var modal = $uibModal.open({ var modal = $uibModal.open({
animation: true, animation: true,
templateUrl: 'app/organization/views/organizationSubvaultsGroups.html', templateUrl: 'app/organization/views/organizationCollectionsGroups.html',
controller: 'organizationSubvaultsGroupsController', controller: 'organizationCollectionsGroupsController',
resolve: { resolve: {
subvault: function () { return subvault; } collection: function () { return collection; }
} }
}); });
@ -70,27 +70,27 @@
}); });
}; };
$scope.delete = function (subvault) { $scope.delete = function (collection) {
if (!confirm('Are you sure you want to delete this subvault (' + subvault.name + ')?')) { if (!confirm('Are you sure you want to delete this collection (' + collection.name + ')?')) {
return; return;
} }
apiService.subvaults.del({ orgId: $state.params.orgId, id: subvault.id }, function () { apiService.collections.del({ orgId: $state.params.orgId, id: collection.id }, function () {
var index = $scope.subvaults.indexOf(subvault); var index = $scope.collections.indexOf(collection);
if (index > -1) { if (index > -1) {
$scope.subvaults.splice(index, 1); $scope.collections.splice(index, 1);
} }
$analytics.eventTrack('Deleted Subvault'); $analytics.eventTrack('Deleted Collection');
toastr.success(subvault.name + ' has been deleted.', 'Subvault Deleted'); toastr.success(collection.name + ' has been deleted.', 'Collection Deleted');
}, function () { }, function () {
toastr.error(subvault.name + ' was not able to be deleted.', 'Error'); toastr.error(collection.name + ' was not able to be deleted.', 'Error');
}); });
}; };
function loadList() { function loadList() {
apiService.subvaults.listOrganization({ orgId: $state.params.orgId }, function (list) { apiService.collections.listOrganization({ orgId: $state.params.orgId }, function (list) {
$scope.subvaults = cipherService.decryptSubvaults(list.Data, $state.params.orgId, true); $scope.collections = cipherService.decryptCollections(list.Data, $state.params.orgId, true);
$scope.loading = false; $scope.loading = false;
}); });
} }

View File

@ -1,23 +1,23 @@
angular angular
.module('bit.organization') .module('bit.organization')
.controller('organizationSubvaultsEditController', function ($scope, $state, $uibModalInstance, apiService, cipherService, .controller('organizationCollectionsEditController', function ($scope, $state, $uibModalInstance, apiService, cipherService,
$analytics, id) { $analytics, id) {
$analytics.eventTrack('organizationSubvaultsEditController', { category: 'Modal' }); $analytics.eventTrack('organizationCollectionsEditController', { category: 'Modal' });
$scope.subvault = {}; $scope.collection = {};
$uibModalInstance.opened.then(function () { $uibModalInstance.opened.then(function () {
apiService.subvaults.get({ orgId: $state.params.orgId, id: id }, function (subvault) { apiService.collections.get({ orgId: $state.params.orgId, id: id }, function (collection) {
$scope.subvault = cipherService.decryptSubvault(subvault); $scope.collection = cipherService.decryptCollection(collection);
}); });
}); });
$scope.submit = function (model) { $scope.submit = function (model) {
var subvault = cipherService.encryptSubvault(model, $state.params.orgId); var collection = cipherService.encryptCollection(model, $state.params.orgId);
$scope.submitPromise = apiService.subvaults.put({ orgId: $state.params.orgId }, subvault, function (response) { $scope.submitPromise = apiService.collections.put({ orgId: $state.params.orgId }, collection, function (response) {
$analytics.eventTrack('Edited Subvault'); $analytics.eventTrack('Edited Collection');
var decSubvault = cipherService.decryptSubvault(response, $state.params.orgId, true); var decCollection = cipherService.decryptCollection(response, $state.params.orgId, true);
$uibModalInstance.close(decSubvault); $uibModalInstance.close(decCollection);
}).$promise; }).$promise;
}; };

View File

@ -1,9 +1,9 @@
angular angular
.module('bit.organization') .module('bit.organization')
.controller('organizationSubvaultsGroupsController', function ($scope, $state, $uibModalInstance, subvault, $analytics) { .controller('organizationCollectionsGroupsController', function ($scope, $state, $uibModalInstance, collection, $analytics) {
$analytics.eventTrack('organizationSubvaultsGroupsController', { category: 'Modal' }); $analytics.eventTrack('organizationCollectionsGroupsController', { category: 'Modal' });
$scope.subvault = subvault; $scope.collection = collection;
$scope.close = function () { $scope.close = function () {
$uibModalInstance.dismiss('cancel'); $uibModalInstance.dismiss('cancel');

View File

@ -1,19 +1,19 @@
angular angular
.module('bit.organization') .module('bit.organization')
.controller('organizationSubvaultsUsersController', function ($scope, $state, $uibModalInstance, apiService, cipherService, .controller('organizationCollectionsUsersController', function ($scope, $state, $uibModalInstance, apiService, cipherService,
$analytics, subvault, toastr) { $analytics, collection, toastr) {
$analytics.eventTrack('organizationSubvaultsUsersController', { category: 'Modal' }); $analytics.eventTrack('organizationCollectionsUsersController', { category: 'Modal' });
$scope.loading = true; $scope.loading = true;
$scope.subvault = subvault; $scope.collection = collection;
$scope.users = []; $scope.users = [];
$uibModalInstance.opened.then(function () { $uibModalInstance.opened.then(function () {
$scope.loading = false; $scope.loading = false;
apiService.subvaultUsers.listSubvault( apiService.collectionUsers.listCollection(
{ {
orgId: $state.params.orgId, orgId: $state.params.orgId,
subvaultId: subvault.id collectionId: collection.id
}, },
function (userList) { function (userList) {
if (userList && userList.Data.length) { if (userList && userList.Data.length) {
@ -27,7 +27,7 @@
type: userList.Data[i].Type, type: userList.Data[i].Type,
status: userList.Data[i].Status, status: userList.Data[i].Status,
readOnly: userList.Data[i].ReadOnly, readOnly: userList.Data[i].ReadOnly,
accessAllSubvaults: userList.Data[i].AccessAllSubvaults accessAllCollections: userList.Data[i].AccessAllCollections
}); });
} }
$scope.users = users; $scope.users = users;
@ -37,13 +37,13 @@
$scope.remove = function (user) { $scope.remove = function (user) {
if (!confirm('Are you sure you want to remove this user (' + user.email + ') from this ' + if (!confirm('Are you sure you want to remove this user (' + user.email + ') from this ' +
'subvault (' + subvault.name + ')?')) { 'collection (' + collection.name + ')?')) {
return; return;
} }
apiService.subvaultUsers.del({ orgId: $state.params.orgId, id: user.id }, null, function () { apiService.collectionUsers.del({ orgId: $state.params.orgId, id: user.id }, null, function () {
toastr.success(user.email + ' has been removed.', 'User Removed'); toastr.success(user.email + ' has been removed.', 'User Removed');
$analytics.eventTrack('Removed User From Subvault'); $analytics.eventTrack('Removed User From Collection');
var index = $scope.users.indexOf(user); var index = $scope.users.indexOf(user);
if (index > -1) { if (index > -1) {
$scope.users.splice(index, 1); $scope.users.splice(index, 1);

View File

@ -4,25 +4,25 @@
.controller('organizationVaultController', function ($scope, apiService, cipherService, $analytics, $q, $state, .controller('organizationVaultController', function ($scope, apiService, cipherService, $analytics, $q, $state,
$localStorage, $uibModal, $filter) { $localStorage, $uibModal, $filter) {
$scope.logins = []; $scope.logins = [];
$scope.subvaults = []; $scope.collections = [];
$scope.loading = true; $scope.loading = true;
$scope.$on('$viewContentLoaded', function () { $scope.$on('$viewContentLoaded', function () {
var subvaultPromise = apiService.subvaults.listOrganization({ orgId: $state.params.orgId }, function (subvaults) { var collectionPromise = apiService.collections.listOrganization({ orgId: $state.params.orgId }, function (collections) {
var decSubvaults = [{ var decCollections = [{
id: null, id: null,
name: 'Unassigned', name: 'Unassigned',
collapsed: $localStorage.collapsedOrgSubvaults && 'unassigned' in $localStorage.collapsedOrgSubvaults collapsed: $localStorage.collapsedOrgCollections && 'unassigned' in $localStorage.collapsedOrgCollections
}]; }];
for (var i = 0; i < subvaults.Data.length; i++) { for (var i = 0; i < collections.Data.length; i++) {
var decSubvault = cipherService.decryptSubvault(subvaults.Data[i], null, true); var decCollection = cipherService.decryptCollection(collections.Data[i], null, true);
decSubvault.collapsed = $localStorage.collapsedOrgSubvaults && decCollection.collapsed = $localStorage.collapsedOrgCollections &&
decSubvault.id in $localStorage.collapsedOrgSubvaults; decCollection.id in $localStorage.collapsedOrgCollections;
decSubvaults.push(decSubvault); decCollections.push(decCollection);
} }
$scope.subvaults = decSubvaults; $scope.collections = decCollections;
}).$promise; }).$promise;
var cipherPromise = apiService.ciphers.listOrganizationDetails({ organizationId: $state.params.orgId }, var cipherPromise = apiService.ciphers.listOrganizationDetails({ organizationId: $state.params.orgId },
@ -39,22 +39,22 @@
$scope.logins = decLogins; $scope.logins = decLogins;
}).$promise; }).$promise;
$q.all([subvaultPromise, cipherPromise]).then(function () { $q.all([collectionPromise, cipherPromise]).then(function () {
$scope.loading = false; $scope.loading = false;
}); });
}); });
$scope.filterBySubvault = function (subvault) { $scope.filterByCollection = function (collection) {
return function (cipher) { return function (cipher) {
if (!cipher.subvaultIds || !cipher.subvaultIds.length) { if (!cipher.collectionIds || !cipher.collectionIds.length) {
return subvault.id === null; return collection.id === null;
} }
return cipher.subvaultIds.indexOf(subvault.id) > -1; return cipher.collectionIds.indexOf(collection.id) > -1;
}; };
}; };
$scope.subvaultSort = function (item) { $scope.collectionSort = function (item) {
if (!item.id) { if (!item.id) {
return ''; return '';
} }
@ -62,58 +62,58 @@
return item.name.toLowerCase(); return item.name.toLowerCase();
}; };
$scope.collapseExpand = function (subvault) { $scope.collapseExpand = function (collection) {
if (!$localStorage.collapsedOrgSubvaults) { if (!$localStorage.collapsedOrgCollections) {
$localStorage.collapsedOrgSubvaults = {}; $localStorage.collapsedOrgCollections = {};
} }
var id = subvault.id || 'unassigned'; var id = collection.id || 'unassigned';
if (id in $localStorage.collapsedOrgSubvaults) { if (id in $localStorage.collapsedOrgCollections) {
delete $localStorage.collapsedOrgSubvaults[id]; delete $localStorage.collapsedOrgCollections[id];
} }
else { else {
$localStorage.collapsedOrgSubvaults[id] = true; $localStorage.collapsedOrgCollections[id] = true;
} }
}; };
$scope.editSubvaults = function (cipher) { $scope.editCollections = function (cipher) {
var modal = $uibModal.open({ var modal = $uibModal.open({
animation: true, animation: true,
templateUrl: 'app/organization/views/organizationVaultLoginSubvaults.html', templateUrl: 'app/organization/views/organizationVaultLoginCollections.html',
controller: 'organizationVaultLoginSubvaultsController', controller: 'organizationVaultLoginCollectionsController',
resolve: { resolve: {
cipher: function () { return cipher; }, cipher: function () { return cipher; },
subvaults: function () { return $scope.subvaults; } collections: function () { return $scope.collections; }
} }
}); });
modal.result.then(function (response) { modal.result.then(function (response) {
if (response.subvaultIds) { if (response.collectionIds) {
cipher.subvaultIds = response.subvaultIds; cipher.collectionIds = response.collectionIds;
} }
}); });
}; };
$scope.removeLogin = function (login, subvault) { $scope.removeLogin = function (login, collection) {
if (!confirm('Are you sure you want to remove this login (' + login.name + ') from the ' + if (!confirm('Are you sure you want to remove this login (' + login.name + ') from the ' +
'subvault (' + subvault.name + ') ?')) { 'collection (' + collection.name + ') ?')) {
return; return;
} }
var request = { var request = {
subvaultIds: [] collectionIds: []
}; };
for (var i = 0; i < login.subvaultIds.length; i++) { for (var i = 0; i < login.collectionIds.length; i++) {
if (login.subvaultIds[i] !== subvault.id) { if (login.collectionIds[i] !== collection.id) {
request.subvaultIds.push(login.subvaultIds[i]); request.collectionIds.push(login.collectionIds[i]);
} }
} }
apiService.ciphers.putSubvaults({ id: login.id }, request).$promise.then(function (response) { apiService.ciphers.putCollections({ id: login.id }, request).$promise.then(function (response) {
$analytics.eventTrack('Removed Login From Subvault'); $analytics.eventTrack('Removed Login From Collection');
login.subvaultIds = request.subvaultIds; login.collectionIds = request.collectionIds;
}); });
}; };

View File

@ -1,78 +1,78 @@
angular angular
.module('bit.organization') .module('bit.organization')
.controller('organizationVaultLoginSubvaultsController', function ($scope, apiService, $uibModalInstance, cipherService, .controller('organizationVaultLoginCollectionsController', function ($scope, apiService, $uibModalInstance, cipherService,
cipher, $analytics, subvaults) { cipher, $analytics, collections) {
$analytics.eventTrack('organizationVaultLoginSubvaultsController', { category: 'Modal' }); $analytics.eventTrack('organizationVaultLoginCollectionsController', { category: 'Modal' });
$scope.cipher = {}; $scope.cipher = {};
$scope.subvaults = []; $scope.collections = [];
$scope.selectedSubvaults = {}; $scope.selectedCollections = {};
$uibModalInstance.opened.then(function () { $uibModalInstance.opened.then(function () {
var subvaultUsed = []; var collectionUsed = [];
for (var i = 0; i < subvaults.length; i++) { for (var i = 0; i < collections.length; i++) {
if (subvaults[i].id) { if (collections[i].id) {
subvaultUsed.push(subvaults[i]); collectionUsed.push(collections[i]);
} }
} }
$scope.subvaults = subvaultUsed; $scope.collections = collectionUsed;
$scope.cipher = cipher; $scope.cipher = cipher;
var selectedSubvaults = {}; var selectedCollections = {};
if ($scope.cipher.subvaultIds) { if ($scope.cipher.collectionIds) {
for (i = 0; i < $scope.cipher.subvaultIds.length; i++) { for (i = 0; i < $scope.cipher.collectionIds.length; i++) {
selectedSubvaults[$scope.cipher.subvaultIds[i]] = true; selectedCollections[$scope.cipher.collectionIds[i]] = true;
} }
} }
$scope.selectedSubvaults = selectedSubvaults; $scope.selectedCollections = selectedCollections;
}); });
$scope.toggleSubvaultSelectionAll = function ($event) { $scope.toggleCollectionSelectionAll = function ($event) {
var subvaults = {}; var collections = {};
if ($event.target.checked) { if ($event.target.checked) {
for (var i = 0; i < $scope.subvaults.length; i++) { for (var i = 0; i < $scope.collections.length; i++) {
subvaults[$scope.subvaults[i].id] = true; collections[$scope.collections[i].id] = true;
} }
} }
$scope.selectedSubvaults = subvaults; $scope.selectedCollections = collections;
}; };
$scope.toggleSubvaultSelection = function (id) { $scope.toggleCollectionSelection = function (id) {
if (id in $scope.selectedSubvaults) { if (id in $scope.selectedCollections) {
delete $scope.selectedSubvaults[id]; delete $scope.selectedCollections[id];
} }
else { else {
$scope.selectedSubvaults[id] = true; $scope.selectedCollections[id] = true;
} }
}; };
$scope.subvaultSelected = function (subvault) { $scope.collectionSelected = function (collection) {
return subvault.id in $scope.selectedSubvaults; return collection.id in $scope.selectedCollections;
}; };
$scope.allSelected = function () { $scope.allSelected = function () {
return Object.keys($scope.selectedSubvaults).length === $scope.subvaults.length; return Object.keys($scope.selectedCollections).length === $scope.collections.length;
}; };
$scope.submit = function () { $scope.submit = function () {
var request = { var request = {
subvaultIds: [] collectionIds: []
}; };
for (var id in $scope.selectedSubvaults) { for (var id in $scope.selectedCollections) {
if ($scope.selectedSubvaults.hasOwnProperty(id)) { if ($scope.selectedCollections.hasOwnProperty(id)) {
request.subvaultIds.push(id); request.collectionIds.push(id);
} }
} }
$scope.submitPromise = apiService.ciphers.putSubvaultsAdmin({ id: cipher.id }, request) $scope.submitPromise = apiService.ciphers.putCollectionsAdmin({ id: cipher.id }, request)
.$promise.then(function (response) { .$promise.then(function (response) {
$analytics.eventTrack('Edited Login Subvaults'); $analytics.eventTrack('Edited Login Collections');
$uibModalInstance.close({ $uibModalInstance.close({
action: 'subvaultsEdit', action: 'collectionsEdit',
subvaultIds: request.subvaultIds collectionIds: request.collectionIds
}); });
}); });
}; };

View File

@ -8,7 +8,7 @@
<div class="callout callout-warning" ng-if="!orgProfile.enabled"> <div class="callout callout-warning" ng-if="!orgProfile.enabled">
<h4><i class="fa fa-warning"></i> Organization Disabled</h4> <h4><i class="fa fa-warning"></i> Organization Disabled</h4>
<p> <p>
This organization is currently disabled. Users will not see your shared logins or subvaults. This organization is currently disabled. Users will not see your shared logins or collections.
Contact us if you would like to reinstate this organization. Contact us if you would like to reinstate this organization.
</p> </p>
<a class="btn btn-default btn-flat" href="https://bitwarden.com/contact/" target="_blank"> <a class="btn btn-default btn-flat" href="https://bitwarden.com/contact/" target="_blank">
@ -20,12 +20,12 @@
<h3 class="box-title">Let's Get Started!</h3> <h3 class="box-title">Let's Get Started!</h3>
</div> </div>
<div class="box-body"> <div class="box-body">
<p>Dashboard features are coming soon. Get started by inviting users and creating your subvaults.</p> <p>Dashboard features are coming soon. Get started by inviting users and creating your collections.</p>
<a class="btn btn-default btn-flat" ui-sref="backend.org.people({orgId: orgProfile.id})"> <a class="btn btn-default btn-flat" ui-sref="backend.org.people({orgId: orgProfile.id})">
Invite Users Invite Users
</a> </a>
<a class="btn btn-default btn-flat" ui-sref="backend.org.subvaults({orgId: orgProfile.id})"> <a class="btn btn-default btn-flat" ui-sref="backend.org.collections({orgId: orgProfile.id})">
Manage Subvaults Manage Collections
</a> </a>
</div> </div>
</div> </div>

View File

@ -5,7 +5,7 @@
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise"> <form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise">
<div class="modal-body"> <div class="modal-body">
<p> <p>
Continue below to delete this organization and all associated data. This data includes any subvaults and Continue below to delete this organization and all associated data. This data includes any collections and
their associated logins. Individual user accounts will remain, though they will not be associated to this their associated logins. Individual user accounts will remain, though they will not be associated to this
organization anymore. organization anymore.
</p> </p>

View File

@ -64,8 +64,8 @@
</td> </td>
<td> <td>
<a href="javascript:void(0)" ng-click="edit(user.id)">{{user.email}}</a> <a href="javascript:void(0)" ng-click="edit(user.id)">{{user.email}}</a>
<i class="fa fa-share-alt text-muted" ng-show="user.accessAllSubvaults" <i class="fa fa-share-alt text-muted" ng-show="user.accessAllCollections"
title="Can Access All Subvaults"></i> title="Can Access All Collections"></i>
<div ng-if="user.name"><small class="text-muted">{{user.name}}</small></div> <div ng-if="user.name"><small class="text-muted">{{user.name}}</small></div>
</td> </td>
<td style="width: 100px;"> <td style="width: 100px;">

View File

@ -15,13 +15,13 @@
<div class="radio"> <div class="radio">
<label> <label>
<input type="radio" id="user-type" ng-model="type" name="Type" value="2" ng-checked="type === 2"> <input type="radio" id="user-type" ng-model="type" name="Type" value="2" ng-checked="type === 2">
<strong>User</strong> - A regular user with access to your organization's subvaults. <strong>User</strong> - A regular user with access to your organization's collections.
</label> </label>
</div> </div>
<div class="radio"> <div class="radio">
<label> <label>
<input type="radio" ng-model="type" name="Type" value="1" ng-checked="type === 1"> <input type="radio" ng-model="type" name="Type" value="1" ng-checked="type === 1">
<strong>Admin</strong> - Admins can manage subvaults and users for your organization. <strong>Admin</strong> - Admins can manage collections and users for your organization.
</label> </label>
</div> </div>
<div class="radio"> <div class="radio">
@ -31,60 +31,60 @@
</label> </label>
</div> </div>
</div> </div>
<h4>Subvault Access</h4> <h4>Collection Access</h4>
<div class="radio"> <div class="radio">
<label> <label>
<input type="radio" ng-model="accessAllSubvaults" name="AccessAllSubvaults" <input type="radio" ng-model="accessAllCollections" name="AccessAllCollections"
ng-value="true" ng-checked="accessAllSubvaults"> ng-value="true" ng-checked="accessAllCollections">
This user can access and modify items in <u>all</u> subvaults. This user can access and modify items in <u>all</u> collections.
</label> </label>
</div> </div>
<div class="radio"> <div class="radio">
<label> <label>
<input type="radio" ng-model="accessAllSubvaults" name="AccessAllSubvaults" <input type="radio" ng-model="accessAllCollections" name="AccessAllCollections"
ng-value="false" ng-checked="!accessAllSubvaults"> ng-value="false" ng-checked="!accessAllCollections">
This user can access only the selected subvaults. This user can access only the selected collections.
</label> </label>
</div> </div>
<div ng-show="!accessAllSubvaults"> <div ng-show="!accessAllCollections">
<div ng-show="loading && !subvaults.length"> <div ng-show="loading && !collections.length">
Loading subvaults... Loading collections...
</div> </div>
<div ng-show="!loading && !subvaults.length"> <div ng-show="!loading && !collections.length">
<p>No subvaults for your organization.</p> <p>No collections for your organization.</p>
</div> </div>
<div class="table-responsive" ng-show="subvaults.length" style="margin: 0;"> <div class="table-responsive" ng-show="collections.length" style="margin: 0;">
<table class="table table-striped table-hover" style="margin: 0;"> <table class="table table-striped table-hover" style="margin: 0;">
<thead> <thead>
<tr> <tr>
<th style="width: 40px;"> <th style="width: 40px;">
<input type="checkbox" <input type="checkbox"
ng-checked="allSelected()" ng-checked="allSelected()"
ng-click="toggleSubvaultSelectionAll($event)"> ng-click="toggleCollectionSelectionAll($event)">
</th> </th>
<th>Name</th> <th>Name</th>
<th style="width: 100px; text-align: center;">Read Only</th> <th style="width: 100px; text-align: center;">Read Only</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="subvault in subvaults | orderBy: ['name']"> <tr ng-repeat="collection in collections | orderBy: ['name']">
<td valign="middle"> <td valign="middle">
<input type="checkbox" <input type="checkbox"
name="selectedSubvaults[]" name="selectedCollections[]"
value="{{subvault.id}}" value="{{collection.id}}"
ng-checked="subvaultSelected(subvault)" ng-checked="collectionSelected(collection)"
ng-click="toggleSubvaultSelection(subvault.id)"> ng-click="toggleCollectionSelection(collection.id)">
</td> </td>
<td valign="middle"> <td valign="middle">
{{subvault.name}} {{collection.name}}
</td> </td>
<td style="text-align: center;" valign="middle"> <td style="text-align: center;" valign="middle">
<input type="checkbox" <input type="checkbox"
name="selectedSubvaultsReadonly[]" name="selectedCollectionsReadonly[]"
value="{{subvault.id}}" value="{{collection.id}}"
ng-disabled="!subvaultSelected(subvault)" ng-disabled="!collectionSelected(collection)"
ng-checked="subvaultSelected(subvault) && selectedSubvaults[subvault.id].readOnly" ng-checked="collectionSelected(collection) && selectedCollections[collection.id].readOnly"
ng-click="toggleSubvaultReadOnlySelection(subvault.id)"> ng-click="toggleCollectionReadOnlySelection(collection.id)">
</td> </td>
</tr> </tr>
</tbody> </tbody>

View File

@ -23,13 +23,13 @@
<div class="radio"> <div class="radio">
<label> <label>
<input type="radio" id="user-type" ng-model="model.type" name="Type" value="User"> <input type="radio" id="user-type" ng-model="model.type" name="Type" value="User">
<strong>User</strong> - A regular user with access to your organization's subvaults. <strong>User</strong> - A regular user with access to your organization's collections.
</label> </label>
</div> </div>
<div class="radio"> <div class="radio">
<label> <label>
<input type="radio" ng-model="model.type" name="Type" value="Admin"> <input type="radio" ng-model="model.type" name="Type" value="Admin">
<strong>Admin</strong> - Admins can manage subvaults and users for your organization. <strong>Admin</strong> - Admins can manage collections and users for your organization.
</label> </label>
</div> </div>
<div class="radio"> <div class="radio">
@ -39,60 +39,60 @@
</label> </label>
</div> </div>
</div> </div>
<h4>Subvault Access</h4> <h4>Collection Access</h4>
<div class="radio"> <div class="radio">
<label> <label>
<input type="radio" ng-model="model.accessAllSubvaults" name="AccessAllSubvaults" <input type="radio" ng-model="model.accessAllCollections" name="AccessAllCollections"
ng-value="true" ng-checked="model.accessAllSubvaults"> ng-value="true" ng-checked="model.accessAllCollections">
This user can access and modify items in <u>all</u> subvaults. This user can access and modify items in <u>all</u> collections.
</label> </label>
</div> </div>
<div class="radio"> <div class="radio">
<label> <label>
<input type="radio" ng-model="model.accessAllSubvaults" name="AccessAllSubvaults" <input type="radio" ng-model="model.accessAllCollections" name="AccessAllCollections"
ng-value="false" ng-checked="!model.accessAllSubvaults"> ng-value="false" ng-checked="!model.accessAllCollections">
This user can access only the selected subvaults. This user can access only the selected collections.
</label> </label>
</div> </div>
<div ng-show="!model.accessAllSubvaults"> <div ng-show="!model.accessAllCollections">
<div ng-show="loading && !subvaults.length"> <div ng-show="loading && !collections.length">
Loading subvaults... Loading collections...
</div> </div>
<div ng-show="!loading && !subvaults.length"> <div ng-show="!loading && !collections.length">
<p>No subvaults for your organization.</p> <p>No collections for your organization.</p>
</div> </div>
<div class="table-responsive" ng-show="subvaults.length" style="margin: 0;"> <div class="table-responsive" ng-show="collections.length" style="margin: 0;">
<table class="table table-striped table-hover" style="margin: 0;"> <table class="table table-striped table-hover" style="margin: 0;">
<thead> <thead>
<tr> <tr>
<th style="width: 40px;"> <th style="width: 40px;">
<input type="checkbox" <input type="checkbox"
ng-checked="allSelected()" ng-checked="allSelected()"
ng-click="toggleSubvaultSelectionAll($event)"> ng-click="toggleCollectionSelectionAll($event)">
</th> </th>
<th>Name</th> <th>Name</th>
<th style="width: 100px; text-align: center;">Read Only</th> <th style="width: 100px; text-align: center;">Read Only</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="subvault in subvaults | orderBy: ['name'] track by subvault.id"> <tr ng-repeat="collection in collections | orderBy: ['name'] track by collection.id">
<td style="width: 40px;" valign="middle"> <td style="width: 40px;" valign="middle">
<input type="checkbox" <input type="checkbox"
name="selectedSubvaults[]" name="selectedCollections[]"
value="{{subvault.id}}" value="{{collection.id}}"
ng-checked="subvaultSelected(subvault)" ng-checked="collectionSelected(collection)"
ng-click="toggleSubvaultSelection(subvault.id)"> ng-click="toggleCollectionSelection(collection.id)">
</td> </td>
<td valign="middle"> <td valign="middle">
{{subvault.name}} {{collection.name}}
</td> </td>
<td style="width: 100px; text-align: center;" valign="middle"> <td style="width: 100px; text-align: center;" valign="middle">
<input type="checkbox" <input type="checkbox"
name="selectedSubvaultsReadonly[]" name="selectedCollectionsReadonly[]"
value="{{subvault.id}}" value="{{collection.id}}"
ng-disabled="!subvaultSelected(subvault)" ng-disabled="!collectionSelected(collection)"
ng-checked="subvaultSelected(subvault) && selectedSubvaults[subvault.id].readOnly" ng-checked="collectionSelected(collection) && selectedCollections[collection.id].readOnly"
ng-click="toggleSubvaultReadOnlySelection(subvault.id)"> ng-click="toggleCollectionReadOnlySelection(collection.id)">
</td> </td>
</tr> </tr>
</tbody> </tbody>

View File

@ -1,6 +1,6 @@
<section class="content-header"> <section class="content-header">
<h1> <h1>
Subvaults Collections
<small>share with your organization</small> <small>share with your organization</small>
</h1> </h1>
</section> </section>
@ -10,33 +10,33 @@
&nbsp; &nbsp;
<div class="box-filters hidden-xs"> <div class="box-filters hidden-xs">
<div class="form-group form-group-sm has-feedback has-feedback-left"> <div class="form-group form-group-sm has-feedback has-feedback-left">
<input type="text" id="search" class="form-control" placeholder="Search subvaults..." <input type="text" id="search" class="form-control" placeholder="Search collections..."
style="width: 200px;" ng-model="filterSearch"> style="width: 200px;" ng-model="filterSearch">
<span class="fa fa-search form-control-feedback text-muted" aria-hidden="true"></span> <span class="fa fa-search form-control-feedback text-muted" aria-hidden="true"></span>
</div> </div>
</div> </div>
<div class="box-tools"> <div class="box-tools">
<button type="button" class="btn btn-primary btn-sm btn-flat" ng-click="add()"> <button type="button" class="btn btn-primary btn-sm btn-flat" ng-click="add()">
<i class="fa fa-fw fa-plus-circle"></i> New Subvault <i class="fa fa-fw fa-plus-circle"></i> New Collection
</button> </button>
</div> </div>
</div> </div>
<div class="box-body" ng-class="{'no-padding': filteredSubvaults.length}"> <div class="box-body" ng-class="{'no-padding': filteredCollections.length}">
<div ng-show="loading && !subvaults.length"> <div ng-show="loading && !collections.length">
Loading... Loading...
</div> </div>
<div ng-show="!filteredSubvaults.length && filterSearch"> <div ng-show="!filteredCollections.length && filterSearch">
No subvaults to list. No collections to list.
</div> </div>
<div ng-show="!loading && !subvaults.length"> <div ng-show="!loading && !collections.length">
<p>There are no subvaults yet for your organization.</p> <p>There are no collections yet for your organization.</p>
<button type="button" ng-click="add()" class="btn btn-default btn-flat">Add a Subvault</button> <button type="button" ng-click="add()" class="btn btn-default btn-flat">Add a Collection</button>
</div> </div>
<div class="table-responsive" ng-show="subvaults.length"> <div class="table-responsive" ng-show="collections.length">
<table class="table table-striped table-hover table-vmiddle"> <table class="table table-striped table-hover table-vmiddle">
<tbody> <tbody>
<tr ng-repeat="subvault in filteredSubvaults = (subvaults | filter: (filterSearch || '') | <tr ng-repeat="collection in filteredCollections = (collections | filter: (filterSearch || '') |
orderBy: ['name']) track by subvault.id"> orderBy: ['name']) track by collection.id">
<td style="width: 70px;"> <td style="width: 70px;">
<div class="btn-group" data-append-to="body"> <div class="btn-group" data-append-to="body">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"> <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
@ -44,17 +44,17 @@
</button> </button>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li> <li>
<a href="javascript:void(0)" ng-click="users(subvault)"> <a href="javascript:void(0)" ng-click="users(collection)">
<i class="fa fa-fw fa-users"></i> Users <i class="fa fa-fw fa-users"></i> Users
</a> </a>
</li> </li>
<li> <li>
<a href="javascript:void(0)" ng-click="groups(subvault)"> <a href="javascript:void(0)" ng-click="groups(collection)">
<i class="fa fa-fw fa-sitemap"></i> Groups <i class="fa fa-fw fa-sitemap"></i> Groups
</a> </a>
</li> </li>
<li> <li>
<a href="javascript:void(0)" ng-click="delete(subvault)" class="text-red"> <a href="javascript:void(0)" ng-click="delete(collection)" class="text-red">
<i class="fa fa-fw fa-trash"></i> Delete <i class="fa fa-fw fa-trash"></i> Delete
</a> </a>
</li> </li>
@ -62,8 +62,8 @@
</div> </div>
</td> </td>
<td valign="middle"> <td valign="middle">
<a href="javascript:void(0)" ng-click="edit(subvault)"> <a href="javascript:void(0)" ng-click="edit(collection)">
{{subvault.name}} {{collection.name}}
</a> </a>
</td> </td>
</tr> </tr>

View File

@ -1,6 +1,6 @@
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button> <button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><i class="fa fa-share-alt"></i> Add Subvault</h4> <h4 class="modal-title"><i class="fa fa-share-alt"></i> Add Collection</h4>
</div> </div>
<form name="form" ng-submit="form.$valid && submit(model)" api-form="submitPromise"> <form name="form" ng-submit="form.$valid && submit(model)" api-form="submitPromise">
<div class="modal-body"> <div class="modal-body">
@ -17,9 +17,9 @@
<div class="callout callout-default"> <div class="callout callout-default">
<h4><i class="fa fa-info-circle"></i> Note</h4> <h4><i class="fa fa-info-circle"></i> Note</h4>
<p> <p>
After creating the subvault, you can associate a user to it by selecting a specific user on the "People" page. After creating the collection, you can associate a user to it by selecting a specific user on the "People" page.
</p> </p>
<p>You can associate logins to the subvault by sharing from "My vault".</p> <p>You can associate logins to the collection by sharing from "My vault".</p>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">

View File

@ -1,8 +1,8 @@
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button> <button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><i class="fa fa-share-alt"></i> Edit Subvault</h4> <h4 class="modal-title"><i class="fa fa-share-alt"></i> Edit Collection</h4>
</div> </div>
<form name="form" ng-submit="form.$valid && submit(subvault)" api-form="submitPromise"> <form name="form" ng-submit="form.$valid && submit(collection)" api-form="submitPromise">
<div class="modal-body"> <div class="modal-body">
<div class="callout callout-danger validation-errors" ng-show="form.$errors"> <div class="callout callout-danger validation-errors" ng-show="form.$errors">
<h4>Errors have occured</h4> <h4>Errors have occured</h4>
@ -12,15 +12,15 @@
</div> </div>
<div class="form-group" show-errors> <div class="form-group" show-errors>
<label for="email">Name</label> <label for="email">Name</label>
<input type="text" id="name" name="Name" ng-model="subvault.name" class="form-control" required api-field /> <input type="text" id="name" name="Name" ng-model="collection.name" class="form-control" required api-field />
</div> </div>
<div class="callout callout-default"> <div class="callout callout-default">
<h4><i class="fa fa-info-circle"></i> Note</h4> <h4><i class="fa fa-info-circle"></i> Note</h4>
<p> <p>
Select "Users" from the listing options to manage existing users for this subvault. Associate new users by Select "Users" from the listing options to manage existing users for this collection. Associate new users by
managing the user's subvault access on the "People" page. managing the user's collection access on the "People" page.
</p> </p>
<p>You can associate logins to this subvault by sharing from "My vault".</p> <p>You can associate logins to this collection by sharing from "My vault".</p>
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">

View File

@ -1,6 +1,6 @@
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button> <button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><i class="fa fa-sitemap"></i> Groups <small>{{subvault.name}}</small></h4> <h4 class="modal-title"><i class="fa fa-sitemap"></i> Groups <small>{{collection.name}}</small></h4>
</div> </div>
<div class="modal-body"> <div class="modal-body">
Groups are coming soon to bitwarden Enterprise organizations. Groups are coming soon to bitwarden Enterprise organizations.

View File

@ -1,6 +1,6 @@
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button> <button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><i class="fa fa-users"></i> User Access <small>{{subvault.name}}</small></h4> <h4 class="modal-title"><i class="fa fa-users"></i> User Access <small>{{collection.name}}</small></h4>
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div ng-show="loading && !users.length"> <div ng-show="loading && !users.length">
@ -8,7 +8,7 @@
</div> </div>
<div ng-show="!loading && !users.length"> <div ng-show="!loading && !users.length">
<p> <p>
No users for this subvault. You can associate a new user to this subvault by No users for this collection. You can associate a new user to this collection by
selecting a specific user on the "People" page. selecting a specific user on the "People" page.
</p> </p>
</div> </div>
@ -43,7 +43,7 @@
<div ng-if="user.name"><small class="text-muted">{{user.name}}</small></div> <div ng-if="user.name"><small class="text-muted">{{user.name}}</small></div>
</td> </td>
<td style="width: 60px;" class="text-right"> <td style="width: 60px;" class="text-right">
<i class="fa fa-share-alt" ng-show="user.accessAllSubvaults" title="Can Access All Subvaults"></i> <i class="fa fa-share-alt" ng-show="user.accessAllCollections" title="Can Access All Collections"></i>
<i class="fa fa-pencil-square-o" ng-show="!user.readOnly" title="Can Edit"></i> <i class="fa fa-pencil-square-o" ng-show="!user.readOnly" title="Can Edit"></i>
</td> </td>
<td style="width: 100px;"> <td style="width: 100px;">

View File

@ -3,37 +3,37 @@
Org<span class="hidden-xs">anization</span> Vault Org<span class="hidden-xs">anization</span> Vault
<small> <small>
<span ng-pluralize <span ng-pluralize
count="subvaults.length > 0 ? subvaults.length - 1 : 0" count="collections.length > 0 ? collections.length - 1 : 0"
when="{'1': '{} subvault', 'other': '{} subvaults'}"></span>, when="{'1': '{} collection', 'other': '{} collections'}"></span>,
<span ng-pluralize count="logins.length" when="{'1': '{} login', 'other': '{} logins'}"></span> <span ng-pluralize count="logins.length" when="{'1': '{} login', 'other': '{} logins'}"></span>
</small> </small>
</h1> </h1>
</section> </section>
<section class="content"> <section class="content">
<p ng-show="loading && !subvaults.length">Loading...</p> <p ng-show="loading && !collections.length">Loading...</p>
<div class="box" ng-class="{'collapsed-box': subvault.collapsed}" ng-repeat="subvault in subvaults | <div class="box" ng-class="{'collapsed-box': collection.collapsed}" ng-repeat="collection in collections |
orderBy: subvaultSort track by subvault.id" orderBy: collectionSort track by collection.id"
ng-show="subvaults.length"> ng-show="collections.length">
<div class="box-header with-border"> <div class="box-header with-border">
<h3 class="box-title"> <h3 class="box-title">
<i class="fa" ng-class="{'fa-share-alt-square': subvault.id, 'fa-sitemap': !subvault.id}"></i> <i class="fa" ng-class="{'fa-share-alt-square': collection.id, 'fa-sitemap': !collection.id}"></i>
{{subvault.name}} {{collection.name}}
<small ng-pluralize count="subvaultLogins.length" when="{'1': '{} login', 'other': '{} logins'}"></small> <small ng-pluralize count="collectionLogins.length" when="{'1': '{} login', 'other': '{} logins'}"></small>
</h3> </h3>
<div class="box-tools"> <div class="box-tools">
<button type="button" class="btn btn-box-tool" data-widget="collapse" title="Collapse/Expand" <button type="button" class="btn btn-box-tool" data-widget="collapse" title="Collapse/Expand"
ng-click="collapseExpand(subvault)"> ng-click="collapseExpand(collection)">
<i class="fa" ng-class="{'fa-minus': !subvault.collapsed, 'fa-plus': subvault.collapsed}"></i> <i class="fa" ng-class="{'fa-minus': !collection.collapsed, 'fa-plus': collection.collapsed}"></i>
</button> </button>
</div> </div>
</div> </div>
<div class="box-body" ng-class="{'no-padding': subvaultLogins.length}"> <div class="box-body" ng-class="{'no-padding': collectionLogins.length}">
<div ng-show="!subvaultLogins.length && subvault.id">No logins in this subvault.</div> <div ng-show="!collectionLogins.length && collection.id">No logins in this collection.</div>
<div ng-show="!subvaultLogins.length && !subvault.id">No unassigned logins.</div> <div ng-show="!collectionLogins.length && !collection.id">No unassigned logins.</div>
<div class="table-responsive" ng-show="subvaultLogins.length"> <div class="table-responsive" ng-show="collectionLogins.length">
<table class="table table-striped table-hover table-vmiddle"> <table class="table table-striped table-hover table-vmiddle">
<tbody> <tbody>
<tr ng-repeat="login in subvaultLogins = (logins | filter: filterBySubvault(subvault) | <tr ng-repeat="login in collectionLogins = (logins | filter: filterByCollection(collection) |
orderBy: ['name', 'username']) track by login.id"> orderBy: ['name', 'username']) track by login.id">
<td style="width: 70px;"> <td style="width: 70px;">
<div class="btn-group" data-append-to="body"> <div class="btn-group" data-append-to="body">
@ -42,13 +42,13 @@
</button> </button>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li> <li>
<a href="javascript:void(0)" ng-click="editSubvaults(login)"> <a href="javascript:void(0)" ng-click="editCollections(login)">
<i class="fa fa-fw fa-share-alt"></i> Subvaults <i class="fa fa-fw fa-share-alt"></i> Collections
</a> </a>
</li> </li>
<li> <li>
<a href="javascript:void(0)" ng-click="removeLogin(login, subvault)" class="text-red" <a href="javascript:void(0)" ng-click="removeLogin(login, collection)" class="text-red"
ng-if="subvault.id"> ng-if="collection.id">
<i class="fa fa-fw fa-remove"></i> Remove <i class="fa fa-fw fa-remove"></i> Remove
</a> </a>
</li> </li>
@ -61,7 +61,7 @@
</div> </div>
</td> </td>
<td> <td>
<a href="javascript:void(0)" ng-click="editSubvaults(login)">{{login.name}}</a> <a href="javascript:void(0)" ng-click="editCollections(login)">{{login.name}}</a>
<div class="text-sm text-muted">{{login.username}}</div> <div class="text-sm text-muted">{{login.username}}</div>
</td> </td>
</tr> </tr>

View File

@ -1,42 +1,42 @@
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button> <button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><i class="fa fa-share-alt"></i> Subvaults <small>{{cipher.name}}</small></h4> <h4 class="modal-title"><i class="fa fa-share-alt"></i> Collections <small>{{cipher.name}}</small></h4>
</div> </div>
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise"> <form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise">
<div class="modal-body"> <div class="modal-body">
<p>Edit the subvaults that this login is being shared with.</p> <p>Edit the collections that this login is being shared with.</p>
<div class="callout callout-danger validation-errors" ng-show="form.$errors"> <div class="callout callout-danger validation-errors" ng-show="form.$errors">
<h4>Errors have occured</h4> <h4>Errors have occured</h4>
<ul> <ul>
<li ng-repeat="e in form.$errors">{{e}}</li> <li ng-repeat="e in form.$errors">{{e}}</li>
</ul> </ul>
</div> </div>
<div ng-show="!subvaults.length" class="callout callout-default"> <div ng-show="!collections.length" class="callout callout-default">
<p>No subvaults to manage.</p> <p>No collections to manage.</p>
</div> </div>
<div class="table-responsive" ng-show="subvaults.length" style="margin: 0;"> <div class="table-responsive" ng-show="collections.length" style="margin: 0;">
<table class="table table-striped table-hover" style="margin: 0;"> <table class="table table-striped table-hover" style="margin: 0;">
<thead> <thead>
<tr> <tr>
<th style="width: 40px;"> <th style="width: 40px;">
<input type="checkbox" <input type="checkbox"
ng-checked="allSelected()" ng-checked="allSelected()"
ng-click="toggleSubvaultSelectionAll($event)"> ng-click="toggleCollectionSelectionAll($event)">
</th> </th>
<th>Name</th> <th>Name</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="subvault in subvaults | orderBy: ['name'] track by subvault.id"> <tr ng-repeat="collection in collections | orderBy: ['name'] track by collection.id">
<td valign="middle"> <td valign="middle">
<input type="checkbox" <input type="checkbox"
name="selectedSubvaults[]" name="selectedCollections[]"
value="{{subvault.id}}" value="{{collection.id}}"
ng-checked="subvaultSelected(subvault)" ng-checked="collectionSelected(collection)"
ng-click="toggleSubvaultSelection(subvault.id)"> ng-click="toggleCollectionSelection(collection.id)">
</td> </td>
<td valign="middle" ng-click="toggleSubvaultSelection(subvault.id)"> <td valign="middle" ng-click="toggleCollectionSelection(collection.id)">
{{subvault.name}} {{collection.name}}
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -44,7 +44,7 @@
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="submit" class="btn btn-primary btn-flat" ng-disabled="form.$loading" ng-show="subvaults.length"> <button type="submit" class="btn btn-primary btn-flat" ng-disabled="form.$loading" ng-show="collections.length">
<i class="fa fa-refresh fa-spin loading-icon" ng-show="form.$loading"></i>Save <i class="fa fa-refresh fa-spin loading-icon" ng-show="form.$loading"></i>Save
</button> </button>
<button type="button" class="btn btn-default btn-flat" ng-click="close()">Close</button> <button type="button" class="btn btn-default btn-flat" ng-click="close()">Close</button>

View File

@ -31,8 +31,8 @@
favorite: { url: _apiUri + '/ciphers/:id/favorite', method: 'POST', params: { id: '@id' } }, favorite: { url: _apiUri + '/ciphers/:id/favorite', method: 'POST', params: { id: '@id' } },
putPartial: { url: _apiUri + '/ciphers/:id/partial', method: 'POST', params: { id: '@id' } }, putPartial: { url: _apiUri + '/ciphers/:id/partial', method: 'POST', params: { id: '@id' } },
putShare: { url: _apiUri + '/ciphers/:id/share', method: 'POST', params: { id: '@id' } }, putShare: { url: _apiUri + '/ciphers/:id/share', method: 'POST', params: { id: '@id' } },
putSubvaults: { url: _apiUri + '/ciphers/:id/subvaults', method: 'POST', params: { id: '@id' } }, putCollections: { url: _apiUri + '/ciphers/:id/collections', method: 'POST', params: { id: '@id' } },
putSubvaultsAdmin: { url: _apiUri + '/ciphers/:id/subvaults-admin', method: 'POST', params: { id: '@id' } }, putCollectionsAdmin: { url: _apiUri + '/ciphers/:id/collections-admin', method: 'POST', params: { id: '@id' } },
del: { url: _apiUri + '/ciphers/:id/delete', method: 'POST', params: { id: '@id' } }, del: { url: _apiUri + '/ciphers/:id/delete', method: 'POST', params: { id: '@id' } },
delAdmin: { url: _apiUri + '/ciphers/:id/delete-admin', method: 'POST', params: { id: '@id' } } delAdmin: { url: _apiUri + '/ciphers/:id/delete-admin', method: 'POST', params: { id: '@id' } }
}); });
@ -63,18 +63,18 @@
del: { url: _apiUri + '/organizations/:orgId/users/:id/delete', method: 'POST', params: { id: '@id', orgId: '@orgId' } } del: { url: _apiUri + '/organizations/:orgId/users/:id/delete', method: 'POST', params: { id: '@id', orgId: '@orgId' } }
}); });
_service.subvaults = $resource(_apiUri + '/organizations/:orgId/subvaults/:id', {}, { _service.collections = $resource(_apiUri + '/organizations/:orgId/collections/:id', {}, {
get: { method: 'GET', params: { id: '@id', orgId: '@orgId' } }, get: { method: 'GET', params: { id: '@id', orgId: '@orgId' } },
listMe: { url: _apiUri + '/subvaults', method: 'GET', params: {} }, listMe: { url: _apiUri + '/collections', method: 'GET', params: {} },
listOrganization: { method: 'GET', params: { orgId: '@orgId' } }, listOrganization: { method: 'GET', params: { orgId: '@orgId' } },
post: { method: 'POST', params: { orgId: '@orgId' } }, post: { method: 'POST', params: { orgId: '@orgId' } },
put: { method: 'POST', params: { id: '@id', orgId: '@orgId' } }, put: { method: 'POST', params: { id: '@id', orgId: '@orgId' } },
del: { url: _apiUri + '/organizations/:orgId/subvaults/:id/delete', method: 'POST', params: { id: '@id', orgId: '@orgId' } } del: { url: _apiUri + '/organizations/:orgId/collections/:id/delete', method: 'POST', params: { id: '@id', orgId: '@orgId' } }
}); });
_service.subvaultUsers = $resource(_apiUri + '/organizations/:orgId/subvaultUsers/:id', {}, { _service.collectionUsers = $resource(_apiUri + '/organizations/:orgId/collectionUsers/:id', {}, {
listSubvault: { url: _apiUri + '/organizations/:orgId/subvaultUsers/:subvaultId', method: 'GET', params: { subvaultId: '@subvaultId', orgId: '@orgId' } }, listCollection: { url: _apiUri + '/organizations/:orgId/collectionUsers/:collectionId', method: 'GET', params: { collectionId: '@collectionId', orgId: '@orgId' } },
del: { url: _apiUri + '/organizations/:orgId/subvaultUsers/:id/delete', method: 'POST', params: { id: '@id', orgId: '@orgId' } } del: { url: _apiUri + '/organizations/:orgId/collectionUsers/:id/delete', method: 'POST', params: { id: '@id', orgId: '@orgId' } }
}); });
_service.accounts = $resource(_apiUri + '/accounts', {}, { _service.accounts = $resource(_apiUri + '/accounts', {}, {

View File

@ -26,7 +26,7 @@ angular
var login = { var login = {
id: encryptedLogin.Id, id: encryptedLogin.Id,
organizationId: encryptedLogin.OrganizationId, organizationId: encryptedLogin.OrganizationId,
subvaultIds: encryptedLogin.SubvaultIds || [], collectionIds: encryptedLogin.CollectionIds || [],
'type': 1, 'type': 1,
folderId: encryptedLogin.FolderId, folderId: encryptedLogin.FolderId,
favorite: encryptedLogin.Favorite, favorite: encryptedLogin.Favorite,
@ -51,7 +51,7 @@ angular
var login = { var login = {
id: encryptedCipher.Id, id: encryptedCipher.Id,
organizationId: encryptedCipher.OrganizationId, organizationId: encryptedCipher.OrganizationId,
subvaultIds: encryptedCipher.SubvaultIds || [], collectionIds: encryptedCipher.CollectionIds || [],
folderId: encryptedCipher.FolderId, folderId: encryptedCipher.FolderId,
favorite: encryptedCipher.Favorite, favorite: encryptedCipher.Favorite,
name: _service.decryptProperty(encryptedCipher.Data.Name, key, false), name: _service.decryptProperty(encryptedCipher.Data.Name, key, false),
@ -90,28 +90,28 @@ angular
}; };
}; };
_service.decryptSubvaults = function (encryptedSubvaults, orgId, catchError) { _service.decryptCollections = function (encryptedCollections, orgId, catchError) {
if (!encryptedSubvaults) throw "encryptedSubvaults is undefined or null"; if (!encryptedCollections) throw "encryptedCollections is undefined or null";
var unencryptedSubvaults = []; var unencryptedCollections = [];
for (var i = 0; i < encryptedSubvaults.length; i++) { for (var i = 0; i < encryptedCollections.length; i++) {
unencryptedSubvaults.push(_service.decryptSubvault(encryptedSubvaults[i], orgId, catchError)); unencryptedCollections.push(_service.decryptCollection(encryptedCollections[i], orgId, catchError));
} }
return unencryptedSubvaults; return unencryptedCollections;
}; };
_service.decryptSubvault = function (encryptedSubvault, orgId, catchError) { _service.decryptCollection = function (encryptedCollection, orgId, catchError) {
if (!encryptedSubvault) throw "encryptedSubvault is undefined or null"; if (!encryptedCollection) throw "encryptedCollection is undefined or null";
catchError = catchError === true ? true : false; catchError = catchError === true ? true : false;
orgId = orgId || encryptedSubvault.OrganizationId; orgId = orgId || encryptedCollection.OrganizationId;
var key = cryptoService.getOrgKey(orgId); var key = cryptoService.getOrgKey(orgId);
return { return {
id: encryptedSubvault.Id, id: encryptedCollection.Id,
name: catchError ? _service.decryptProperty(encryptedSubvault.Name, key, false) : name: catchError ? _service.decryptProperty(encryptedCollection.Name, key, false) :
cryptoService.decrypt(encryptedSubvault.Name, key) cryptoService.decrypt(encryptedCollection.Name, key)
}; };
}; };
@ -182,23 +182,23 @@ angular
}; };
}; };
_service.encryptSubvaults = function (unencryptedSubvaults, orgId) { _service.encryptCollections = function (unencryptedCollections, orgId) {
if (!unencryptedSubvaults) throw "unencryptedSubvaults is undefined or null"; if (!unencryptedCollections) throw "unencryptedCollections is undefined or null";
var encryptedSubvaults = []; var encryptedCollections = [];
for (var i = 0; i < unencryptedSubvaults.length; i++) { for (var i = 0; i < unencryptedCollections.length; i++) {
encryptedSubvaults.push(_service.encryptSubvault(unencryptedSubvaults[i], orgId)); encryptedCollections.push(_service.encryptCollection(unencryptedCollections[i], orgId));
} }
return encryptedSubvaults; return encryptedCollections;
}; };
_service.encryptSubvault = function (unencryptedSubvault, orgId) { _service.encryptCollection = function (unencryptedCollection, orgId) {
if (!unencryptedSubvault) throw "unencryptedSubvault is undefined or null"; if (!unencryptedCollection) throw "unencryptedCollection is undefined or null";
return { return {
id: unencryptedSubvault.id, id: unencryptedCollection.id,
name: cryptoService.encrypt(unencryptedSubvault.name, cryptoService.getOrgKey(orgId)) name: cryptoService.encrypt(unencryptedCollection.name, cryptoService.getOrgKey(orgId))
}; };
}; };

View File

@ -62,7 +62,7 @@
Free Free
<span>For personal users to share with 1 other user.</span> <span>For personal users to share with 1 other user.</span>
<span>- Limit 2 users (including you)</span> <span>- Limit 2 users (including you)</span>
<span>- Limit 2 subvaults</span> <span>- Limit 2 collections</span>
<span class="bottom-line"> <span class="bottom-line">
Free forever Free forever
</span> </span>
@ -74,7 +74,7 @@
Personal Personal
<span>For personal users such as families &amp; friends.</span> <span>For personal users such as families &amp; friends.</span>
<span>- Add and share with up to 10 users (5 included with base price)</span> <span>- Add and share with up to 10 users (5 included with base price)</span>
<span>- Create unlimited subvaults</span> <span>- Create unlimited collections</span>
<span>- Priority customer support</span> <span>- Priority customer support</span>
<span>- 7 day free trial, cancel anytime</span> <span>- 7 day free trial, cancel anytime</span>
<span class="bottom-line"> <span class="bottom-line">
@ -89,7 +89,7 @@
Teams Teams
<span>For businesses and other team organizations.</span> <span>For businesses and other team organizations.</span>
<span>- Add and share with unlimited users</span> <span>- Add and share with unlimited users</span>
<span>- Create unlimited subvaults</span> <span>- Create unlimited collections</span>
<span>- Priority customer support</span> <span>- Priority customer support</span>
<span>- 7 day free trial, cancel anytime</span> <span>- 7 day free trial, cancel anytime</span>
<span class="bottom-line"> <span class="bottom-line">

View File

@ -264,18 +264,18 @@
}); });
}; };
$scope.subvaults = function (login) { $scope.collections = function (login) {
var modal = $uibModal.open({ var modal = $uibModal.open({
animation: true, animation: true,
templateUrl: 'app/vault/views/vaultLoginSubvaults.html', templateUrl: 'app/vault/views/vaultLoginCollections.html',
controller: 'vaultLoginSubvaultsController', controller: 'vaultLoginCollectionsController',
resolve: { resolve: {
loginId: function () { return login.id; } loginId: function () { return login.id; }
} }
}); });
modal.result.then(function (response) { modal.result.then(function (response) {
if (response.subvaultIds && !response.subvaultIds.length) { if (response.collectionIds && !response.collectionIds.length) {
removeLoginFromScopes(login); removeLoginFromScopes(login);
} }
}); });

View File

@ -1,15 +1,15 @@
angular angular
.module('bit.vault') .module('bit.vault')
.controller('vaultLoginSubvaultsController', function ($scope, apiService, $uibModalInstance, cipherService, .controller('vaultLoginCollectionsController', function ($scope, apiService, $uibModalInstance, cipherService,
loginId, $analytics) { loginId, $analytics) {
$analytics.eventTrack('vaultLoginSubvaultsController', { category: 'Modal' }); $analytics.eventTrack('vaultLoginCollectionsController', { category: 'Modal' });
$scope.login = {}; $scope.login = {};
$scope.readOnly = false; $scope.readOnly = false;
$scope.loadingLogin = true; $scope.loadingLogin = true;
$scope.loadingSubvaults = true; $scope.loadingCollections = true;
$scope.selectedSubvaults = {}; $scope.selectedCollections = {};
$scope.subvaults = []; $scope.collections = [];
$uibModalInstance.opened.then(function () { $uibModalInstance.opened.then(function () {
apiService.ciphers.getFullDetails({ id: loginId }).$promise.then(function (cipher) { apiService.ciphers.getFullDetails({ id: loginId }).$promise.then(function (cipher) {
@ -21,13 +21,13 @@
$scope.login = cipherService.decryptLoginPreview(cipher); $scope.login = cipherService.decryptLoginPreview(cipher);
} }
var subvaults = {}; var collections = {};
if (cipher.SubvaultIds) { if (cipher.CollectionIds) {
for (var i = 0; i < cipher.SubvaultIds.length; i++) { for (var i = 0; i < cipher.CollectionIds.length; i++) {
subvaults[cipher.SubvaultIds[i]] = true; collections[cipher.CollectionIds[i]] = true;
} }
} }
$scope.selectedSubvaults = subvaults; $scope.selectedCollections = collections;
return cipher; return cipher;
} }
@ -35,72 +35,72 @@
return null; return null;
}).then(function (cipher) { }).then(function (cipher) {
if (!cipher) { if (!cipher) {
$scope.loadingSubvaults = false; $scope.loadingCollections = false;
return; return;
} }
apiService.subvaults.listMe(function (response) { apiService.collections.listMe(function (response) {
var subvaults = []; var collections = [];
for (var i = 0; i < response.Data.length; i++) { for (var i = 0; i < response.Data.length; i++) {
if (response.Data[i].OrganizationId !== cipher.OrganizationId) { if (response.Data[i].OrganizationId !== cipher.OrganizationId) {
continue; continue;
} }
var decSubvault = cipherService.decryptSubvault(response.Data[i]); var decCollection = cipherService.decryptCollection(response.Data[i]);
subvaults.push(decSubvault); collections.push(decCollection);
} }
$scope.loadingSubvaults = false; $scope.loadingCollections = false;
$scope.subvaults = subvaults; $scope.collections = collections;
}); });
}); });
}); });
$scope.toggleSubvaultSelectionAll = function ($event) { $scope.toggleCollectionSelectionAll = function ($event) {
var subvaults = {}; var collections = {};
if ($event.target.checked) { if ($event.target.checked) {
for (var i = 0; i < $scope.subvaults.length; i++) { for (var i = 0; i < $scope.collections.length; i++) {
subvaults[$scope.subvaults[i].id] = true; collections[$scope.collections[i].id] = true;
} }
} }
$scope.selectedSubvaults = subvaults; $scope.selectedCollections = collections;
}; };
$scope.toggleSubvaultSelection = function (id) { $scope.toggleCollectionSelection = function (id) {
if (id in $scope.selectedSubvaults) { if (id in $scope.selectedCollections) {
delete $scope.selectedSubvaults[id]; delete $scope.selectedCollections[id];
} }
else { else {
$scope.selectedSubvaults[id] = true; $scope.selectedCollections[id] = true;
} }
}; };
$scope.subvaultSelected = function (subvault) { $scope.collectionSelected = function (collection) {
return subvault.id in $scope.selectedSubvaults; return collection.id in $scope.selectedCollections;
}; };
$scope.allSelected = function () { $scope.allSelected = function () {
return Object.keys($scope.selectedSubvaults).length === $scope.subvaults.length; return Object.keys($scope.selectedCollections).length === $scope.collections.length;
}; };
$scope.submit = function () { $scope.submit = function () {
var request = { var request = {
subvaultIds: [] collectionIds: []
}; };
for (var id in $scope.selectedSubvaults) { for (var id in $scope.selectedCollections) {
if ($scope.selectedSubvaults.hasOwnProperty(id)) { if ($scope.selectedCollections.hasOwnProperty(id)) {
request.subvaultIds.push(id); request.collectionIds.push(id);
} }
} }
$scope.submitPromise = apiService.ciphers.putSubvaults({ id: loginId }, request) $scope.submitPromise = apiService.ciphers.putCollections({ id: loginId }, request)
.$promise.then(function (response) { .$promise.then(function (response) {
$analytics.eventTrack('Edited Login Subvaults'); $analytics.eventTrack('Edited Login Collections');
$uibModalInstance.close({ $uibModalInstance.close({
action: 'subvaultsEdit', action: 'collectionsEdit',
subvaultIds: request.subvaultIds collectionIds: request.collectionIds
}); });
}); });
}; };

View File

@ -6,11 +6,11 @@
$analytics.eventTrack('vaultShareController', { category: 'Modal' }); $analytics.eventTrack('vaultShareController', { category: 'Modal' });
$scope.model = {}; $scope.model = {};
$scope.login = {}; $scope.login = {};
$scope.subvaults = []; $scope.collections = [];
$scope.selectedSubvaults = {}; $scope.selectedCollections = {};
$scope.organizations = []; $scope.organizations = [];
var organizationSubvaultCounts = {}; var organizationCollectionCounts = {};
$scope.loadingSubvaults = true; $scope.loadingCollections = true;
$scope.readOnly = false; $scope.readOnly = false;
apiService.logins.get({ id: loginId }).$promise.then(function (login) { apiService.logins.get({ id: loginId }).$promise.then(function (login) {
@ -38,7 +38,7 @@
name: profile.organizations[i].name name: profile.organizations[i].name
}); });
organizationSubvaultCounts[profile.organizations[i].id] = 0; organizationCollectionCounts[profile.organizations[i].id] = 0;
if (!setFirstOrg) { if (!setFirstOrg) {
setFirstOrg = true; setFirstOrg = true;
@ -49,45 +49,45 @@
$scope.organizations = orgs; $scope.organizations = orgs;
apiService.subvaults.listMe(function (response) { apiService.collections.listMe(function (response) {
var subvaults = []; var collections = [];
for (var i = 0; i < response.Data.length; i++) { for (var i = 0; i < response.Data.length; i++) {
var decSubvault = cipherService.decryptSubvault(response.Data[i]); var decCollection = cipherService.decryptCollection(response.Data[i]);
decSubvault.organizationId = response.Data[i].OrganizationId; decCollection.organizationId = response.Data[i].OrganizationId;
subvaults.push(decSubvault); collections.push(decCollection);
organizationSubvaultCounts[decSubvault.organizationId]++; organizationCollectionCounts[decCollection.organizationId]++;
} }
$scope.subvaults = subvaults; $scope.collections = collections;
$scope.loadingSubvaults = false; $scope.loadingCollections = false;
}); });
} }
}); });
$scope.toggleSubvaultSelectionAll = function ($event) { $scope.toggleCollectionSelectionAll = function ($event) {
var subvaults = {}; var collections = {};
if ($event.target.checked) { if ($event.target.checked) {
for (var i = 0; i < $scope.subvaults.length; i++) { for (var i = 0; i < $scope.collections.length; i++) {
if ($scope.model.organizationId && $scope.subvaults[i].organizationId === $scope.model.organizationId) { if ($scope.model.organizationId && $scope.collections[i].organizationId === $scope.model.organizationId) {
subvaults[$scope.subvaults[i].id] = true; collections[$scope.collections[i].id] = true;
} }
} }
} }
$scope.selectedSubvaults = subvaults; $scope.selectedCollections = collections;
}; };
$scope.toggleSubvaultSelection = function (id) { $scope.toggleCollectionSelection = function (id) {
if (id in $scope.selectedSubvaults) { if (id in $scope.selectedCollections) {
delete $scope.selectedSubvaults[id]; delete $scope.selectedCollections[id];
} }
else { else {
$scope.selectedSubvaults[id] = true; $scope.selectedCollections[id] = true;
} }
}; };
$scope.subvaultSelected = function (subvault) { $scope.collectionSelected = function (collection) {
return subvault.id in $scope.selectedSubvaults; return collection.id in $scope.selectedCollections;
}; };
$scope.allSelected = function () { $scope.allSelected = function () {
@ -95,11 +95,11 @@
return false; return false;
} }
return Object.keys($scope.selectedSubvaults).length === organizationSubvaultCounts[$scope.model.organizationId]; return Object.keys($scope.selectedCollections).length === organizationCollectionCounts[$scope.model.organizationId];
}; };
$scope.orgChanged = function () { $scope.orgChanged = function () {
$scope.selectedSubvaults = {}; $scope.selectedCollections = {};
}; };
$scope.submitPromise = null; $scope.submitPromise = null;
@ -107,13 +107,13 @@
$scope.login.organizationId = model.organizationId; $scope.login.organizationId = model.organizationId;
var request = { var request = {
subvaultIds: [], collectionIds: [],
cipher: cipherService.encryptLogin($scope.login) cipher: cipherService.encryptLogin($scope.login)
}; };
for (var id in $scope.selectedSubvaults) { for (var id in $scope.selectedCollections) {
if ($scope.selectedSubvaults.hasOwnProperty(id)) { if ($scope.selectedCollections.hasOwnProperty(id)) {
request.subvaultIds.push(id); request.collectionIds.push(id);
} }
} }

View File

@ -1,24 +1,24 @@
angular angular
.module('bit.vault') .module('bit.vault')
.controller('vaultSubvaultsController', function ($scope, apiService, cipherService, $analytics, $q, $localStorage, .controller('vaultCollectionsController', function ($scope, apiService, cipherService, $analytics, $q, $localStorage,
$uibModal, $filter, $rootScope) { $uibModal, $filter, $rootScope) {
$scope.logins = []; $scope.logins = [];
$scope.subvaults = []; $scope.collections = [];
$scope.loading = true; $scope.loading = true;
$scope.$on('$viewContentLoaded', function () { $scope.$on('$viewContentLoaded', function () {
var subvaultPromise = apiService.subvaults.listMe({}, function (subvaults) { var collectionPromise = apiService.collections.listMe({}, function (collections) {
var decSubvaults = []; var decCollections = [];
for (var i = 0; i < subvaults.Data.length; i++) { for (var i = 0; i < collections.Data.length; i++) {
var decSubvault = cipherService.decryptSubvault(subvaults.Data[i], null, true); var decCollection = cipherService.decryptCollection(collections.Data[i], null, true);
decSubvault.collapsed = $localStorage.collapsedSubvaults && decCollection.collapsed = $localStorage.collapsedCollections &&
decSubvault.id in $localStorage.collapsedSubvaults; decCollection.id in $localStorage.collapsedCollections;
decSubvaults.push(decSubvault); decCollections.push(decCollection);
} }
$scope.subvaults = decSubvaults; $scope.collections = decCollections;
}).$promise; }).$promise;
var cipherPromise = apiService.ciphers.listDetails({}, function (ciphers) { var cipherPromise = apiService.ciphers.listDetails({}, function (ciphers) {
@ -34,27 +34,27 @@
$scope.logins = decLogins; $scope.logins = decLogins;
}).$promise; }).$promise;
$q.all([subvaultPromise, cipherPromise]).then(function () { $q.all([collectionPromise, cipherPromise]).then(function () {
$scope.loading = false; $scope.loading = false;
}); });
}); });
$scope.filterBySubvault = function (subvault) { $scope.filterByCollection = function (collection) {
return function (cipher) { return function (cipher) {
return cipher.subvaultIds.indexOf(subvault.id) > -1; return cipher.collectionIds.indexOf(collection.id) > -1;
}; };
}; };
$scope.collapseExpand = function (subvault) { $scope.collapseExpand = function (collection) {
if (!$localStorage.collapsedSubvaults) { if (!$localStorage.collapsedCollections) {
$localStorage.collapsedSubvaults = {}; $localStorage.collapsedCollections = {};
} }
if (subvault.id in $localStorage.collapsedSubvaults) { if (collection.id in $localStorage.collapsedCollections) {
delete $localStorage.collapsedSubvaults[subvault.id]; delete $localStorage.collapsedCollections[collection.id];
} }
else { else {
$localStorage.collapsedSubvaults[subvault.id] = true; $localStorage.collapsedCollections[collection.id] = true;
} }
}; };
@ -92,47 +92,47 @@
}); });
}; };
$scope.editSubvaults = function (login) { $scope.editCollections = function (login) {
var modal = $uibModal.open({ var modal = $uibModal.open({
animation: true, animation: true,
templateUrl: 'app/vault/views/vaultLoginSubvaults.html', templateUrl: 'app/vault/views/vaultLoginCollections.html',
controller: 'vaultLoginSubvaultsController', controller: 'vaultLoginCollectionsController',
resolve: { resolve: {
loginId: function () { return login.id; } loginId: function () { return login.id; }
} }
}); });
modal.result.then(function (response) { modal.result.then(function (response) {
if (response.subvaultIds) { if (response.collectionIds) {
login.subvaultIds = response.subvaultIds; login.collectionIds = response.collectionIds;
if (!response.subvaultIds.length) { if (!response.collectionIds.length) {
removeRootLogin(findRootLogin(login)); removeRootLogin(findRootLogin(login));
} }
} }
}); });
}; };
$scope.removeLogin = function (login, subvault) { $scope.removeLogin = function (login, collection) {
if (!confirm('Are you sure you want to remove this login (' + login.name + ') from the ' + if (!confirm('Are you sure you want to remove this login (' + login.name + ') from the ' +
'subvault (' + subvault.name + ') ?')) { 'collection (' + collection.name + ') ?')) {
return; return;
} }
var request = { var request = {
subvaultIds: [] collectionIds: []
}; };
for (var i = 0; i < login.subvaultIds.length; i++) { for (var i = 0; i < login.collectionIds.length; i++) {
if (login.subvaultIds[i] !== subvault.id) { if (login.collectionIds[i] !== collection.id) {
request.subvaultIds.push(login.subvaultIds[i]); request.collectionIds.push(login.collectionIds[i]);
} }
} }
apiService.ciphers.putSubvaults({ id: login.id }, request).$promise.then(function (response) { apiService.ciphers.putCollections({ id: login.id }, request).$promise.then(function (response) {
$analytics.eventTrack('Removed From Subvault'); $analytics.eventTrack('Removed From Collection');
login.subvaultIds = request.subvaultIds; login.collectionIds = request.collectionIds;
if (!login.subvaultIds.length) { if (!login.collectionIds.length) {
removeRootLogin(findRootLogin(login)); removeRootLogin(findRootLogin(login));
} }
}); });

View File

@ -67,8 +67,8 @@
</a> </a>
</li> </li>
<li ng-show="login.organizationId"> <li ng-show="login.organizationId">
<a href="javascript:void(0)" ng-click="subvaults(login)"> <a href="javascript:void(0)" ng-click="collections(login)">
<i class="fa fa-fw fa-share-alt"></i> Subvaults <i class="fa fa-fw fa-share-alt"></i> Collections
</a> </a>
</li> </li>
<li> <li>
@ -154,8 +154,8 @@
</a> </a>
</li> </li>
<li ng-show="login.organizationId"> <li ng-show="login.organizationId">
<a href="javascript:void(0)" ng-click="subvaults(login)"> <a href="javascript:void(0)" ng-click="collections(login)">
<i class="fa fa-fw fa-share-alt"></i> Subvaults <i class="fa fa-fw fa-share-alt"></i> Collections
</a> </a>
</li> </li>
<li> <li>

View File

@ -1,45 +1,45 @@
<div class="modal-header"> <div class="modal-header">
<button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button> <button type="button" class="close" ng-click="close()" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><i class="fa fa-share-alt"></i> Subvaults <small>{{login.name}}</small></h4> <h4 class="modal-title"><i class="fa fa-share-alt"></i> Collections <small>{{login.name}}</small></h4>
</div> </div>
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise"> <form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise">
<div class="modal-body"> <div class="modal-body">
<p>Edit the subvaults that this login is being shared with.</p> <p>Edit the collections that this login is being shared with.</p>
<div class="callout callout-danger validation-errors" ng-show="form.$errors"> <div class="callout callout-danger validation-errors" ng-show="form.$errors">
<h4>Errors have occured</h4> <h4>Errors have occured</h4>
<ul> <ul>
<li ng-repeat="e in form.$errors">{{e}}</li> <li ng-repeat="e in form.$errors">{{e}}</li>
</ul> </ul>
</div> </div>
<div ng-show="loadingSubvaults && !subvaults.length"> <div ng-show="loadingCollections && !collections.length">
Loading... Loading...
</div> </div>
<div ng-show="!loadingSubvaults && !subvaults.length" class="callout callout-default"> <div ng-show="!loadingCollections && !collections.length" class="callout callout-default">
<p>No subvaults to manage.</p> <p>No collections to manage.</p>
</div> </div>
<div class="table-responsive" ng-show="subvaults.length" style="margin: 0;"> <div class="table-responsive" ng-show="collections.length" style="margin: 0;">
<table class="table table-striped table-hover" style="margin: 0;"> <table class="table table-striped table-hover" style="margin: 0;">
<thead> <thead>
<tr> <tr>
<th style="width: 40px;"> <th style="width: 40px;">
<input type="checkbox" <input type="checkbox"
ng-checked="allSelected()" ng-checked="allSelected()"
ng-click="toggleSubvaultSelectionAll($event)"> ng-click="toggleCollectionSelectionAll($event)">
</th> </th>
<th>Name</th> <th>Name</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="subvault in subvaults | orderBy: ['name']"> <tr ng-repeat="collection in collections | orderBy: ['name']">
<td valign="middle"> <td valign="middle">
<input type="checkbox" <input type="checkbox"
name="selectedSubvaults[]" name="selectedCollections[]"
value="{{subvault.id}}" value="{{collection.id}}"
ng-checked="subvaultSelected(subvault)" ng-checked="collectionSelected(collection)"
ng-click="toggleSubvaultSelection(subvault.id)"> ng-click="toggleCollectionSelection(collection.id)">
</td> </td>
<td valign="middle" ng-click="toggleSubvaultSelection(subvault.id)"> <td valign="middle" ng-click="toggleCollectionSelection(collection.id)">
{{subvault.name}} {{collection.name}}
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -47,7 +47,7 @@
</div> </div>
</div> </div>
<div class="modal-footer"> <div class="modal-footer">
<button type="submit" class="btn btn-primary btn-flat" ng-disabled="form.$loading" ng-show="subvaults.length"> <button type="submit" class="btn btn-primary btn-flat" ng-disabled="form.$loading" ng-show="collections.length">
<i class="fa fa-refresh fa-spin loading-icon" ng-show="form.$loading"></i>Save <i class="fa fa-refresh fa-spin loading-icon" ng-show="form.$loading"></i>Save
</button> </button>
<button type="button" class="btn btn-default btn-flat" ng-click="close()">Close</button> <button type="button" class="btn btn-default btn-flat" ng-click="close()">Close</button>

View File

@ -26,38 +26,38 @@
<option ng-repeat="org in organizations | orderBy: ['name']" value="{{org.id}}">{{org.name}}</option> <option ng-repeat="org in organizations | orderBy: ['name']" value="{{org.id}}">{{org.name}}</option>
</select> </select>
</div> </div>
<h4 ng-hide="!loadingSubvaults && !orgSubvaults.length">Subvault Access</h4> <h4 ng-hide="!loadingCollections && !orgCollections.length">Collection Access</h4>
<div ng-show="loadingSubvaults && !orgSubvaults.length"> <div ng-show="loadingCollections && !orgCollections.length">
<p>Loading...</p> <p>Loading...</p>
</div> </div>
<div ng-show="!loadingSubvaults && !orgSubvaults.length" class="callout callout-default"> <div ng-show="!loadingCollections && !orgCollections.length" class="callout callout-default">
<h4><i class="fa fa-info-circle"></i> No Subvaults</h4> <h4><i class="fa fa-info-circle"></i> No Collections</h4>
<p>You do not have write access to any subvaults for this organization.</p> <p>You do not have write access to any collections for this organization.</p>
</div> </div>
<div class="table-responsive" ng-show="orgSubvaults.length" style="margin: 0;"> <div class="table-responsive" ng-show="orgCollections.length" style="margin: 0;">
<table class="table table-striped table-hover" style="margin: 0;"> <table class="table table-striped table-hover" style="margin: 0;">
<thead> <thead>
<tr> <tr>
<th style="width: 40px;"> <th style="width: 40px;">
<input type="checkbox" <input type="checkbox"
ng-checked="allSelected()" ng-checked="allSelected()"
ng-click="toggleSubvaultSelectionAll($event)"> ng-click="toggleCollectionSelectionAll($event)">
</th> </th>
<th>Name</th> <th>Name</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
<tr ng-repeat="subvault in orgSubvaults = <tr ng-repeat="collection in orgCollections =
(subvaults | filter: { organizationId: model.organizationId } | orderBy: ['name'])"> (collections | filter: { organizationId: model.organizationId } | orderBy: ['name'])">
<td valign="middle"> <td valign="middle">
<input type="checkbox" <input type="checkbox"
name="selectedSubvaults[]" name="selectedCollections[]"
value="{{subvault.id}}" value="{{collection.id}}"
ng-checked="subvaultSelected(subvault)" ng-checked="collectionSelected(collection)"
ng-click="toggleSubvaultSelection(subvault.id)"> ng-click="toggleCollectionSelection(collection.id)">
</td> </td>
<td valign="middle" ng-click="toggleSubvaultSelection(subvault.id)"> <td valign="middle" ng-click="toggleCollectionSelection(collection.id)">
{{subvault.name}} {{collection.name}}
</td> </td>
</tr> </tr>
</tbody> </tbody>

View File

@ -1,57 +1,57 @@
<section class="content-header"> <section class="content-header">
<h1> <h1>
Subvaults Collections
<small> <small>
<span ng-pluralize count="subvaults.length" when="{'1': '{} subvault', 'other': '{} subvaults'}"></span>, <span ng-pluralize count="collections.length" when="{'1': '{} collection', 'other': '{} collections'}"></span>,
<span ng-pluralize count="logins.length" when="{'1': '{} login', 'other': '{} logins'}"></span> <span ng-pluralize count="logins.length" when="{'1': '{} login', 'other': '{} logins'}"></span>
</small> </small>
</h1> </h1>
</section> </section>
<section class="content"> <section class="content">
<div ng-show="loading && !subvaults.length"> <div ng-show="loading && !collections.length">
<p>Loading...</p> <p>Loading...</p>
</div> </div>
<div class="callout callout-default" style="background: #fff;" ng-show="!loading && !subvaults.length"> <div class="callout callout-default" style="background: #fff;" ng-show="!loading && !collections.length">
<h4><i class="fa fa-info-circle"></i> No Subvaults</h4> <h4><i class="fa fa-info-circle"></i> No Collections</h4>
<p> <p>
You do not have any subvaults being shared with you. You do not have any collections being shared with you.
</p> </p>
<p> <p>
Subvaults allow you to share logins with other bitwarden users. To start using subvaults create an organization or Collections allow you to share logins with other bitwarden users. To start using collections create an organization or
ask an existing organization to invite you. ask an existing organization to invite you.
</p> </p>
<a ui-sref="backend.user.settingsCreateOrg" class="btn btn-default btn-flat"> <a ui-sref="backend.user.settingsCreateOrg" class="btn btn-default btn-flat">
Create an Organization Create an Organization
</a> </a>
</div> </div>
<div class="box" ng-class="{'collapsed-box': subvault.collapsed}" ng-repeat="subvault in subvaults | <div class="box" ng-class="{'collapsed-box': collection.collapsed}" ng-repeat="collection in collections |
orderBy: ['name'] track by subvault.id" orderBy: ['name'] track by collection.id"
ng-show="subvaults.length"> ng-show="collections.length">
<div class="box-header with-border"> <div class="box-header with-border">
<h3 class="box-title"> <h3 class="box-title">
<i class="fa fa-share-alt-square"></i> <i class="fa fa-share-alt-square"></i>
{{subvault.name}} {{collection.name}}
<small ng-pluralize count="subvaultLogins.length" when="{'1': '{} login', 'other': '{} logins'}"></small> <small ng-pluralize count="collectionLogins.length" when="{'1': '{} login', 'other': '{} logins'}"></small>
</h3> </h3>
<div class="box-tools"> <div class="box-tools">
<button type="button" class="btn btn-box-tool" data-widget="collapse" title="Collapse/Expand" <button type="button" class="btn btn-box-tool" data-widget="collapse" title="Collapse/Expand"
ng-click="collapseExpand(subvault)"> ng-click="collapseExpand(collection)">
<i class="fa" ng-class="{'fa-minus': !subvault.collapsed, 'fa-plus': subvault.collapsed}"></i> <i class="fa" ng-class="{'fa-minus': !collection.collapsed, 'fa-plus': collection.collapsed}"></i>
</button> </button>
</div> </div>
</div> </div>
<div class="box-body" ng-class="{'no-padding': subvaultLogins.length}"> <div class="box-body" ng-class="{'no-padding': collectionLogins.length}">
<div ng-show="!subvaultLogins.length"> <div ng-show="!collectionLogins.length">
<p>No logins in this subvault.</p> <p>No logins in this collection.</p>
<p> <p>
Share a login to this subvault by selecting <i class="fa fa-share-alt"></i> <b>Share</b> or Share a login to this collection by selecting <i class="fa fa-share-alt"></i> <b>Share</b> or
<i class="fa fa-share-alt"></i> <b>Subvaults</b> from the login's options (<i class="fa fa-cog"></i>) menu. <i class="fa fa-share-alt"></i> <b>Collections</b> from the login's options (<i class="fa fa-cog"></i>) menu.
</p> </p>
</div> </div>
<div class="table-responsive" ng-show="subvaultLogins.length"> <div class="table-responsive" ng-show="collectionLogins.length">
<table class="table table-striped table-hover table-vmiddle"> <table class="table table-striped table-hover table-vmiddle">
<tbody> <tbody>
<tr ng-repeat="login in subvaultLogins = (logins | filter: filterBySubvault(subvault) | <tr ng-repeat="login in collectionLogins = (logins | filter: filterByCollection(collection) |
orderBy: ['name', 'username']) track by login.id"> orderBy: ['name', 'username']) track by login.id">
<td style="width: 70px;"> <td style="width: 70px;">
<div class="btn-group" data-append-to="body"> <div class="btn-group" data-append-to="body">
@ -65,12 +65,12 @@
</a> </a>
</li> </li>
<li> <li>
<a href="javascript:void(0)" ng-click="editSubvaults(login)"> <a href="javascript:void(0)" ng-click="editCollections(login)">
<i class="fa fa-fw fa-share-alt"></i> Subvaults <i class="fa fa-fw fa-share-alt"></i> Collections
</a> </a>
</li> </li>
<li> <li>
<a href="javascript:void(0)" ng-click="removeLogin(login, subvault)" class="text-red"> <a href="javascript:void(0)" ng-click="removeLogin(login, collection)" class="text-red">
<i class="fa fa-fw fa-remove"></i> Remove <i class="fa fa-fw fa-remove"></i> Remove
</a> </a>
</li> </li>

View File

@ -41,9 +41,9 @@
<i class="fa fa-lock fa-fw"></i> <span>Vault</span> <i class="fa fa-lock fa-fw"></i> <span>Vault</span>
</a> </a>
</li> </li>
<li ng-class="{active: $state.is('backend.org.subvaults')}"> <li ng-class="{active: $state.is('backend.org.collections')}">
<a ui-sref="backend.org.subvaults({orgId: params.orgId})"> <a ui-sref="backend.org.collections({orgId: params.orgId})">
<i class="fa fa-share-alt fa-fw"></i> <span>Subvaults</span> <i class="fa fa-share-alt fa-fw"></i> <span>Collections</span>
</a> </a>
</li> </li>
<li ng-class="{active: $state.is('backend.org.people')}"> <li ng-class="{active: $state.is('backend.org.people')}">

View File

@ -54,11 +54,11 @@
</li> </li>
</ul> </ul>
</li> </li>
<li class="treeview" ng-class="{active: $state.is('backend.user.subvaults')}"> <li class="treeview" ng-class="{active: $state.is('backend.user.collections')}">
<a ui-sref="backend.user.subvaults"> <a ui-sref="backend.user.collections">
<small class="label pull-right bg-orange">NEW</small> <small class="label pull-right bg-orange">NEW</small>
<i class="fa fa-share-alt fa-fw"></i> <span>Subvaults</span> <i class="fa fa-share-alt fa-fw"></i> <span>Collections</span>
</a> </a>
</li> </li>
<li class="treeview" ng-class="{active: $state.is('backend.user.tools')}"> <li class="treeview" ng-class="{active: $state.is('backend.user.tools')}">

View File

@ -126,18 +126,18 @@
<script src="app/vault/vaultEditFolderController.js"></script> <script src="app/vault/vaultEditFolderController.js"></script>
<script src="app/vault/vaultAddFolderController.js"></script> <script src="app/vault/vaultAddFolderController.js"></script>
<script src="app/vault/vaultShareController.js"></script> <script src="app/vault/vaultShareController.js"></script>
<script src="app/vault/vaultSubvaultsController.js"></script> <script src="app/vault/vaultCollectionsController.js"></script>
<script src="app/vault/vaultLoginSubvaultsController.js"></script> <script src="app/vault/vaultLoginCollectionsController.js"></script>
<script src="app/organization/organizationModule.js"></script> <script src="app/organization/organizationModule.js"></script>
<script src="app/organization/organizationDashboardController.js"></script> <script src="app/organization/organizationDashboardController.js"></script>
<script src="app/organization/organizationPeopleController.js"></script> <script src="app/organization/organizationPeopleController.js"></script>
<script src="app/organization/organizationPeopleInviteController.js"></script> <script src="app/organization/organizationPeopleInviteController.js"></script>
<script src="app/organization/organizationPeopleEditController.js"></script> <script src="app/organization/organizationPeopleEditController.js"></script>
<script src="app/organization/organizationSubvaultsController.js"></script> <script src="app/organization/organizationCollectionsController.js"></script>
<script src="app/organization/organizationSubvaultsAddController.js"></script> <script src="app/organization/organizationCollectionsAddController.js"></script>
<script src="app/organization/organizationSubvaultsEditController.js"></script> <script src="app/organization/organizationCollectionsEditController.js"></script>
<script src="app/organization/organizationSubvaultsUsersController.js"></script> <script src="app/organization/organizationCollectionsUsersController.js"></script>
<script src="app/organization/organizationSettingsController.js"></script> <script src="app/organization/organizationSettingsController.js"></script>
<script src="app/organization/organizationBillingController.js"></script> <script src="app/organization/organizationBillingController.js"></script>
<script src="app/organization/organizationBillingChangePaymentController.js"></script> <script src="app/organization/organizationBillingChangePaymentController.js"></script>
@ -145,9 +145,9 @@
<script src="app/organization/organizationDeleteController.js"></script> <script src="app/organization/organizationDeleteController.js"></script>
<script src="app/organization/organizationBillingChangePlanController.js"></script> <script src="app/organization/organizationBillingChangePlanController.js"></script>
<script src="app/organization/organizationVaultController.js"></script> <script src="app/organization/organizationVaultController.js"></script>
<script src="app/organization/organizationVaultLoginSubvaultsController.js"></script> <script src="app/organization/organizationVaultLoginCollectionsController.js"></script>
<script src="app/organization/organizationGroupsController.js"></script> <script src="app/organization/organizationGroupsController.js"></script>
<script src="app/organization/organizationSubvaultsGroupsController.js"></script> <script src="app/organization/organizationCollectionsGroupsController.js"></script>
<script src="app/settings/settingsModule.js"></script> <script src="app/settings/settingsModule.js"></script>
<script src="app/settings/settingsController.js"></script> <script src="app/settings/settingsController.js"></script>