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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,7 +8,7 @@
<div class="callout callout-warning" ng-if="!orgProfile.enabled">
<h4><i class="fa fa-warning"></i> Organization Disabled</h4>
<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.
</p>
<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>
</div>
<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})">
Invite Users
</a>
<a class="btn btn-default btn-flat" ui-sref="backend.org.subvaults({orgId: orgProfile.id})">
Manage Subvaults
<a class="btn btn-default btn-flat" ui-sref="backend.org.collections({orgId: orgProfile.id})">
Manage Collections
</a>
</div>
</div>

View File

@ -5,7 +5,7 @@
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise">
<div class="modal-body">
<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
organization anymore.
</p>

View File

@ -64,8 +64,8 @@
</td>
<td>
<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"
title="Can Access All Subvaults"></i>
<i class="fa fa-share-alt text-muted" ng-show="user.accessAllCollections"
title="Can Access All Collections"></i>
<div ng-if="user.name"><small class="text-muted">{{user.name}}</small></div>
</td>
<td style="width: 100px;">

View File

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

View File

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

View File

@ -1,6 +1,6 @@
<section class="content-header">
<h1>
Subvaults
Collections
<small>share with your organization</small>
</h1>
</section>
@ -10,33 +10,33 @@
&nbsp;
<div class="box-filters hidden-xs">
<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">
<span class="fa fa-search form-control-feedback text-muted" aria-hidden="true"></span>
</div>
</div>
<div class="box-tools">
<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>
</div>
</div>
<div class="box-body" ng-class="{'no-padding': filteredSubvaults.length}">
<div ng-show="loading && !subvaults.length">
<div class="box-body" ng-class="{'no-padding': filteredCollections.length}">
<div ng-show="loading && !collections.length">
Loading...
</div>
<div ng-show="!filteredSubvaults.length && filterSearch">
No subvaults to list.
<div ng-show="!filteredCollections.length && filterSearch">
No collections to list.
</div>
<div ng-show="!loading && !subvaults.length">
<p>There are no subvaults yet for your organization.</p>
<button type="button" ng-click="add()" class="btn btn-default btn-flat">Add a Subvault</button>
<div ng-show="!loading && !collections.length">
<p>There are no collections yet for your organization.</p>
<button type="button" ng-click="add()" class="btn btn-default btn-flat">Add a Collection</button>
</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">
<tbody>
<tr ng-repeat="subvault in filteredSubvaults = (subvaults | filter: (filterSearch || '') |
orderBy: ['name']) track by subvault.id">
<tr ng-repeat="collection in filteredCollections = (collections | filter: (filterSearch || '') |
orderBy: ['name']) track by collection.id">
<td style="width: 70px;">
<div class="btn-group" data-append-to="body">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown">
@ -44,17 +44,17 @@
</button>
<ul class="dropdown-menu">
<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
</a>
</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
</a>
</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
</a>
</li>
@ -62,8 +62,8 @@
</div>
</td>
<td valign="middle">
<a href="javascript:void(0)" ng-click="edit(subvault)">
{{subvault.name}}
<a href="javascript:void(0)" ng-click="edit(collection)">
{{collection.name}}
</a>
</td>
</tr>

View File

@ -1,6 +1,6 @@
<div class="modal-header">
<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>
<form name="form" ng-submit="form.$valid && submit(model)" api-form="submitPromise">
<div class="modal-body">
@ -17,9 +17,9 @@
<div class="callout callout-default">
<h4><i class="fa fa-info-circle"></i> Note</h4>
<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>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 class="modal-footer">

View File

@ -1,8 +1,8 @@
<div class="modal-header">
<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>
<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="callout callout-danger validation-errors" ng-show="form.$errors">
<h4>Errors have occured</h4>
@ -12,15 +12,15 @@
</div>
<div class="form-group" show-errors>
<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 class="callout callout-default">
<h4><i class="fa fa-info-circle"></i> Note</h4>
<p>
Select "Users" from the listing options to manage existing users for this subvault. Associate new users by
managing the user's subvault access on the "People" page.
Select "Users" from the listing options to manage existing users for this collection. Associate new users by
managing the user's collection access on the "People" page.
</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 class="modal-footer">

View File

@ -1,6 +1,6 @@
<div class="modal-header">
<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 class="modal-body">
Groups are coming soon to bitwarden Enterprise organizations.

View File

@ -1,6 +1,6 @@
<div class="modal-header">
<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 class="modal-body">
<div ng-show="loading && !users.length">
@ -8,7 +8,7 @@
</div>
<div ng-show="!loading && !users.length">
<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.
</p>
</div>
@ -43,7 +43,7 @@
<div ng-if="user.name"><small class="text-muted">{{user.name}}</small></div>
</td>
<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>
</td>
<td style="width: 100px;">

View File

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

View File

@ -1,42 +1,42 @@
<div class="modal-header">
<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>
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise">
<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">
<h4>Errors have occured</h4>
<ul>
<li ng-repeat="e in form.$errors">{{e}}</li>
</ul>
</div>
<div ng-show="!subvaults.length" class="callout callout-default">
<p>No subvaults to manage.</p>
<div ng-show="!collections.length" class="callout callout-default">
<p>No collections to manage.</p>
</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;">
<thead>
<tr>
<th style="width: 40px;">
<input type="checkbox"
ng-checked="allSelected()"
ng-click="toggleSubvaultSelectionAll($event)">
ng-click="toggleCollectionSelectionAll($event)">
</th>
<th>Name</th>
</tr>
</thead>
<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">
<input type="checkbox"
name="selectedSubvaults[]"
value="{{subvault.id}}"
ng-checked="subvaultSelected(subvault)"
ng-click="toggleSubvaultSelection(subvault.id)">
name="selectedCollections[]"
value="{{collection.id}}"
ng-checked="collectionSelected(collection)"
ng-click="toggleCollectionSelection(collection.id)">
</td>
<td valign="middle" ng-click="toggleSubvaultSelection(subvault.id)">
{{subvault.name}}
<td valign="middle" ng-click="toggleCollectionSelection(collection.id)">
{{collection.name}}
</td>
</tr>
</tbody>
@ -44,7 +44,7 @@
</div>
</div>
<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
</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' } },
putPartial: { url: _apiUri + '/ciphers/:id/partial', 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' } },
putSubvaultsAdmin: { url: _apiUri + '/ciphers/:id/subvaults-admin', method: 'POST', params: { id: '@id' } },
putCollections: { url: _apiUri + '/ciphers/:id/collections', 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' } },
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' } }
});
_service.subvaults = $resource(_apiUri + '/organizations/:orgId/subvaults/:id', {}, {
_service.collections = $resource(_apiUri + '/organizations/:orgId/collections/:id', {}, {
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' } },
post: { method: 'POST', params: { 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', {}, {
listSubvault: { url: _apiUri + '/organizations/:orgId/subvaultUsers/:subvaultId', method: 'GET', params: { subvaultId: '@subvaultId', orgId: '@orgId' } },
del: { url: _apiUri + '/organizations/:orgId/subvaultUsers/:id/delete', method: 'POST', params: { id: '@id', orgId: '@orgId' } }
_service.collectionUsers = $resource(_apiUri + '/organizations/:orgId/collectionUsers/:id', {}, {
listCollection: { url: _apiUri + '/organizations/:orgId/collectionUsers/:collectionId', method: 'GET', params: { collectionId: '@collectionId', orgId: '@orgId' } },
del: { url: _apiUri + '/organizations/:orgId/collectionUsers/:id/delete', method: 'POST', params: { id: '@id', orgId: '@orgId' } }
});
_service.accounts = $resource(_apiUri + '/accounts', {}, {

View File

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

View File

@ -62,7 +62,7 @@
Free
<span>For personal users to share with 1 other user.</span>
<span>- Limit 2 users (including you)</span>
<span>- Limit 2 subvaults</span>
<span>- Limit 2 collections</span>
<span class="bottom-line">
Free forever
</span>
@ -74,7 +74,7 @@
Personal
<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>- Create unlimited subvaults</span>
<span>- Create unlimited collections</span>
<span>- Priority customer support</span>
<span>- 7 day free trial, cancel anytime</span>
<span class="bottom-line">
@ -89,7 +89,7 @@
Teams
<span>For businesses and other team organizations.</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>- 7 day free trial, cancel anytime</span>
<span class="bottom-line">

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,45 +1,45 @@
<div class="modal-header">
<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>
<form name="form" ng-submit="form.$valid && submit()" api-form="submitPromise">
<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">
<h4>Errors have occured</h4>
<ul>
<li ng-repeat="e in form.$errors">{{e}}</li>
</ul>
</div>
<div ng-show="loadingSubvaults && !subvaults.length">
<div ng-show="loadingCollections && !collections.length">
Loading...
</div>
<div ng-show="!loadingSubvaults && !subvaults.length" class="callout callout-default">
<p>No subvaults to manage.</p>
<div ng-show="!loadingCollections && !collections.length" class="callout callout-default">
<p>No collections to manage.</p>
</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;">
<thead>
<tr>
<th style="width: 40px;">
<input type="checkbox"
ng-checked="allSelected()"
ng-click="toggleSubvaultSelectionAll($event)">
ng-click="toggleCollectionSelectionAll($event)">
</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="subvault in subvaults | orderBy: ['name']">
<tr ng-repeat="collection in collections | orderBy: ['name']">
<td valign="middle">
<input type="checkbox"
name="selectedSubvaults[]"
value="{{subvault.id}}"
ng-checked="subvaultSelected(subvault)"
ng-click="toggleSubvaultSelection(subvault.id)">
name="selectedCollections[]"
value="{{collection.id}}"
ng-checked="collectionSelected(collection)"
ng-click="toggleCollectionSelection(collection.id)">
</td>
<td valign="middle" ng-click="toggleSubvaultSelection(subvault.id)">
{{subvault.name}}
<td valign="middle" ng-click="toggleCollectionSelection(collection.id)">
{{collection.name}}
</td>
</tr>
</tbody>
@ -47,7 +47,7 @@
</div>
</div>
<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
</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>
</select>
</div>
<h4 ng-hide="!loadingSubvaults && !orgSubvaults.length">Subvault Access</h4>
<div ng-show="loadingSubvaults && !orgSubvaults.length">
<h4 ng-hide="!loadingCollections && !orgCollections.length">Collection Access</h4>
<div ng-show="loadingCollections && !orgCollections.length">
<p>Loading...</p>
</div>
<div ng-show="!loadingSubvaults && !orgSubvaults.length" class="callout callout-default">
<h4><i class="fa fa-info-circle"></i> No Subvaults</h4>
<p>You do not have write access to any subvaults for this organization.</p>
<div ng-show="!loadingCollections && !orgCollections.length" class="callout callout-default">
<h4><i class="fa fa-info-circle"></i> No Collections</h4>
<p>You do not have write access to any collections for this organization.</p>
</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;">
<thead>
<tr>
<th style="width: 40px;">
<input type="checkbox"
ng-checked="allSelected()"
ng-click="toggleSubvaultSelectionAll($event)">
ng-click="toggleCollectionSelectionAll($event)">
</th>
<th>Name</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="subvault in orgSubvaults =
(subvaults | filter: { organizationId: model.organizationId } | orderBy: ['name'])">
<tr ng-repeat="collection in orgCollections =
(collections | filter: { organizationId: model.organizationId } | orderBy: ['name'])">
<td valign="middle">
<input type="checkbox"
name="selectedSubvaults[]"
value="{{subvault.id}}"
ng-checked="subvaultSelected(subvault)"
ng-click="toggleSubvaultSelection(subvault.id)">
name="selectedCollections[]"
value="{{collection.id}}"
ng-checked="collectionSelected(collection)"
ng-click="toggleCollectionSelection(collection.id)">
</td>
<td valign="middle" ng-click="toggleSubvaultSelection(subvault.id)">
{{subvault.name}}
<td valign="middle" ng-click="toggleCollectionSelection(collection.id)">
{{collection.name}}
</td>
</tr>
</tbody>

View File

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

View File

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

View File

@ -54,11 +54,11 @@
</li>
</ul>
</li>
<li class="treeview" ng-class="{active: $state.is('backend.user.subvaults')}">
<a ui-sref="backend.user.subvaults">
<li class="treeview" ng-class="{active: $state.is('backend.user.collections')}">
<a ui-sref="backend.user.collections">
<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>
</li>
<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/vaultAddFolderController.js"></script>
<script src="app/vault/vaultShareController.js"></script>
<script src="app/vault/vaultSubvaultsController.js"></script>
<script src="app/vault/vaultLoginSubvaultsController.js"></script>
<script src="app/vault/vaultCollectionsController.js"></script>
<script src="app/vault/vaultLoginCollectionsController.js"></script>
<script src="app/organization/organizationModule.js"></script>
<script src="app/organization/organizationDashboardController.js"></script>
<script src="app/organization/organizationPeopleController.js"></script>
<script src="app/organization/organizationPeopleInviteController.js"></script>
<script src="app/organization/organizationPeopleEditController.js"></script>
<script src="app/organization/organizationSubvaultsController.js"></script>
<script src="app/organization/organizationSubvaultsAddController.js"></script>
<script src="app/organization/organizationSubvaultsEditController.js"></script>
<script src="app/organization/organizationSubvaultsUsersController.js"></script>
<script src="app/organization/organizationCollectionsController.js"></script>
<script src="app/organization/organizationCollectionsAddController.js"></script>
<script src="app/organization/organizationCollectionsEditController.js"></script>
<script src="app/organization/organizationCollectionsUsersController.js"></script>
<script src="app/organization/organizationSettingsController.js"></script>
<script src="app/organization/organizationBillingController.js"></script>
<script src="app/organization/organizationBillingChangePaymentController.js"></script>
@ -145,9 +145,9 @@
<script src="app/organization/organizationDeleteController.js"></script>
<script src="app/organization/organizationBillingChangePlanController.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/organizationSubvaultsGroupsController.js"></script>
<script src="app/organization/organizationCollectionsGroupsController.js"></script>
<script src="app/settings/settingsModule.js"></script>
<script src="app/settings/settingsController.js"></script>