mirror of
https://github.com/bitwarden/browser.git
synced 2025-02-17 01:31:25 +01:00
re-factor vault listings
This commit is contained in:
parent
bbb69bba26
commit
dcb0416fd6
@ -190,7 +190,10 @@ angular
|
||||
url: '/organization/:orgId/vault?viewEvents&search',
|
||||
templateUrl: 'app/organization/views/organizationVault.html',
|
||||
controller: 'organizationVaultController',
|
||||
data: { pageTitle: 'Organization Vault' }
|
||||
data: {
|
||||
pageTitle: 'Organization Vault',
|
||||
controlSidebar: true
|
||||
}
|
||||
})
|
||||
.state('backend.org.groups', {
|
||||
url: '/organization/:orgId/groups?search',
|
||||
@ -349,7 +352,7 @@ angular
|
||||
// user is guaranteed to be authenticated becuase of previous check
|
||||
if (toState.name.indexOf('backend.org.') > -1 && toParams.orgId) {
|
||||
// clear vault rootScope when visiting org admin section
|
||||
$rootScope.vaultCiphers = $rootScope.vaultGroupings = null;
|
||||
$rootScope.vaultCiphers = $rootScope.vaultFolders = $rootScope.vaultCollections = null;
|
||||
|
||||
authService.getUserProfile().then(function (profile) {
|
||||
var orgs = profile.organizations;
|
||||
|
@ -49,10 +49,6 @@ angular
|
||||
vm.openControlSidebar = vm.usingControlSidebar && $document.width() > 768;
|
||||
});
|
||||
|
||||
$scope.$on('setSearchVaultText', function (event, val) {
|
||||
vm.searchVaultText = val;
|
||||
});
|
||||
|
||||
$scope.addCipher = function () {
|
||||
$scope.$broadcast('vaultAddCipher');
|
||||
};
|
||||
|
@ -51,14 +51,6 @@ angular
|
||||
$state.go('backend.org.dashboard', { orgId: org.id });
|
||||
};
|
||||
|
||||
$scope.searchVault = function () {
|
||||
$state.go('backend.user.vault');
|
||||
};
|
||||
|
||||
$scope.searchOrganizationVault = function () {
|
||||
$state.go('backend.org.vault', { orgId: $state.params.orgId });
|
||||
};
|
||||
|
||||
$scope.isOrgOwner = function (org) {
|
||||
return org && org.type === constants.orgUserType.owner;
|
||||
};
|
||||
|
@ -2,12 +2,12 @@
|
||||
.module('bit.organization')
|
||||
|
||||
.controller('organizationVaultAddCipherController', function ($scope, apiService, $uibModalInstance, cryptoService,
|
||||
cipherService, passwordService, $analytics, authService, orgId, $uibModal, constants) {
|
||||
cipherService, passwordService, $analytics, authService, orgId, $uibModal, constants, selectedType) {
|
||||
$analytics.eventTrack('organizationVaultAddCipherController', { category: 'Modal' });
|
||||
$scope.constants = constants;
|
||||
$scope.selectedType = constants.cipherType.login.toString();
|
||||
$scope.selectedType = selectedType ? selectedType.toString() : constants.cipherType.login.toString();
|
||||
$scope.cipher = {
|
||||
type: constants.cipherType.login,
|
||||
type: selectedType || constants.cipherType.login,
|
||||
login: {
|
||||
uris: [{
|
||||
uri: null,
|
||||
|
@ -2,11 +2,18 @@
|
||||
.module('bit.organization')
|
||||
|
||||
.controller('organizationVaultController', function ($scope, apiService, cipherService, $analytics, $q, $state,
|
||||
$localStorage, $uibModal, $filter, authService, $uibModalStack) {
|
||||
$localStorage, $uibModal, $filter, authService, $uibModalStack, constants, $timeout) {
|
||||
$scope.ciphers = [];
|
||||
$scope.collections = [];
|
||||
$scope.loading = true;
|
||||
$scope.useEvents = false;
|
||||
$scope.constants = constants;
|
||||
$scope.filter = undefined;
|
||||
$scope.selectedType = undefined;
|
||||
$scope.selectedCollection = undefined;
|
||||
$scope.selectedAll = true;
|
||||
$scope.selectedTitle = 'All';
|
||||
$scope.selectedIcon = 'fa-th';
|
||||
|
||||
$scope.$on('$viewContentLoaded', function () {
|
||||
authService.getUserProfile().then(function (profile) {
|
||||
@ -19,14 +26,11 @@
|
||||
var collectionPromise = apiService.collections.listOrganization({ orgId: $state.params.orgId }, function (collections) {
|
||||
var decCollections = [{
|
||||
id: null,
|
||||
name: 'Unassigned',
|
||||
collapsed: $localStorage.collapsedOrgCollections && 'unassigned' in $localStorage.collapsedOrgCollections
|
||||
name: 'Unassigned'
|
||||
}];
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
@ -51,7 +55,7 @@
|
||||
|
||||
if ($state.params.search) {
|
||||
$uibModalStack.dismissAll();
|
||||
$scope.$emit('setSearchVaultText', $state.params.search);
|
||||
$scope.searchVaultText = $state.params.search;
|
||||
}
|
||||
|
||||
if ($state.params.viewEvents) {
|
||||
@ -64,16 +68,6 @@
|
||||
});
|
||||
});
|
||||
|
||||
$scope.filterByCollection = function (collection) {
|
||||
return function (cipher) {
|
||||
if (!cipher.collectionIds || !cipher.collectionIds.length) {
|
||||
return collection.id === null;
|
||||
}
|
||||
|
||||
return cipher.collectionIds.indexOf(collection.id) > -1;
|
||||
};
|
||||
};
|
||||
|
||||
$scope.collectionSort = function (item) {
|
||||
if (!item.id) {
|
||||
return '';
|
||||
@ -82,21 +76,6 @@
|
||||
return item.name.toLowerCase();
|
||||
};
|
||||
|
||||
$scope.collapseExpand = function (collection) {
|
||||
if (!$localStorage.collapsedOrgCollections) {
|
||||
$localStorage.collapsedOrgCollections = {};
|
||||
}
|
||||
|
||||
var id = collection.id || 'unassigned';
|
||||
|
||||
if (id in $localStorage.collapsedOrgCollections) {
|
||||
delete $localStorage.collapsedOrgCollections[id];
|
||||
}
|
||||
else {
|
||||
$localStorage.collapsedOrgCollections[id] = true;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.editCipher = function (cipher) {
|
||||
var editModel = $uibModal.open({
|
||||
animation: true,
|
||||
@ -136,7 +115,8 @@
|
||||
templateUrl: 'app/vault/views/vaultAddCipher.html',
|
||||
controller: 'organizationVaultAddCipherController',
|
||||
resolve: {
|
||||
orgId: function () { return $state.params.orgId; }
|
||||
orgId: function () { return $state.params.orgId; },
|
||||
selectedType: function () { return $scope.selectedType; }
|
||||
}
|
||||
});
|
||||
|
||||
@ -205,28 +185,6 @@
|
||||
});
|
||||
};
|
||||
|
||||
$scope.removeCipher = function (cipher, collection) {
|
||||
if (!confirm('Are you sure you want to remove this item (' + cipher.name + ') from the ' +
|
||||
'collection (' + collection.name + ') ?')) {
|
||||
return;
|
||||
}
|
||||
|
||||
var request = {
|
||||
collectionIds: []
|
||||
};
|
||||
|
||||
for (var i = 0; i < cipher.collectionIds.length; i++) {
|
||||
if (cipher.collectionIds[i] !== collection.id) {
|
||||
request.collectionIds.push(cipher.collectionIds[i]);
|
||||
}
|
||||
}
|
||||
|
||||
apiService.ciphers.putCollections({ id: cipher.id }, request).$promise.then(function (response) {
|
||||
$analytics.eventTrack('Removed Cipher From Collection');
|
||||
cipher.collectionIds = request.collectionIds;
|
||||
});
|
||||
};
|
||||
|
||||
$scope.deleteCipher = function (cipher) {
|
||||
if (!confirm('Are you sure you want to delete this item (' + cipher.name + ')?')) {
|
||||
return;
|
||||
@ -240,4 +198,72 @@
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.filterCollection = function (col) {
|
||||
resetSelected();
|
||||
$scope.selectedCollection = col;
|
||||
$scope.selectedIcon = 'fa-cube';
|
||||
$scope.filter = function (c) {
|
||||
return c.collectionIds && c.collectionIds.indexOf(col.id) > -1;
|
||||
};
|
||||
fixLayout();
|
||||
};
|
||||
|
||||
$scope.filterType = function (t) {
|
||||
resetSelected();
|
||||
$scope.selectedType = t;
|
||||
switch (t) {
|
||||
case constants.cipherType.login:
|
||||
$scope.selectedTitle = 'Login';
|
||||
$scope.selectedIcon = 'fa-globe';
|
||||
break;
|
||||
case constants.cipherType.card:
|
||||
$scope.selectedTitle = 'Card';
|
||||
$scope.selectedIcon = 'fa-credit-card';
|
||||
break;
|
||||
case constants.cipherType.identity:
|
||||
$scope.selectedTitle = 'Identity';
|
||||
$scope.selectedIcon = 'fa-id-card-o';
|
||||
break;
|
||||
case constants.cipherType.secureNote:
|
||||
$scope.selectedTitle = 'Secure Note';
|
||||
$scope.selectedIcon = 'fa-sticky-note-o';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
$scope.filter = function (c) {
|
||||
return c.type === t;
|
||||
};
|
||||
fixLayout();
|
||||
};
|
||||
|
||||
$scope.filterAll = function () {
|
||||
resetSelected();
|
||||
$scope.selectedAll = true;
|
||||
$scope.selectedTitle = 'All';
|
||||
$scope.selectedIcon = 'fa-th';
|
||||
$scope.filter = null;
|
||||
fixLayout();
|
||||
};
|
||||
|
||||
function resetSelected() {
|
||||
$scope.selectedCollection = undefined;
|
||||
$scope.selectedType = undefined;
|
||||
$scope.selectedAll = false;
|
||||
}
|
||||
|
||||
function fixLayout() {
|
||||
if ($.AdminLTE && $.AdminLTE.layout) {
|
||||
$timeout(function () {
|
||||
$.AdminLTE.layout.fix();
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.cipherFilter = function () {
|
||||
return function (cipher) {
|
||||
return !$scope.filter || $scope.filter(cipher);
|
||||
};
|
||||
};
|
||||
});
|
||||
|
@ -22,7 +22,7 @@
|
||||
<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 collections.</p>
|
||||
<p>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>
|
||||
|
@ -10,31 +10,22 @@
|
||||
</h1>
|
||||
</section>
|
||||
<section class="content">
|
||||
<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 && (!main.searchVaultText || collectionCiphers.length)">
|
||||
<p ng-show="loading">Loading...</p>
|
||||
<div class="box" ng-show="!loading">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
<i class="fa" ng-class="{'fa-cube': collection.id, 'fa-sitemap': !collection.id}"></i>
|
||||
{{collection.name}}
|
||||
<small ng-pluralize count="collectionCiphers.length" when="{'1': '{} item', 'other': '{} items'}"></small>
|
||||
<i class="fa {{selectedIcon}}"></i>
|
||||
{{selectedCollection ? selectedCollection.name : selectedTitle}}
|
||||
<small ng-pluralize count="filteredCiphers.length" when="{'1': '{} item', 'other': '{} items'}"></small>
|
||||
</h3>
|
||||
<div class="box-tools">
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse" title="Collapse/Expand"
|
||||
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': collectionCiphers.length}">
|
||||
<div ng-show="!collectionCiphers.length && collection.id">No items in this collection.</div>
|
||||
<div ng-show="!collectionCiphers.length && !collection.id">No unassigned items.</div>
|
||||
<div class="table-responsive" ng-show="collectionCiphers.length">
|
||||
<div class="box-body" ng-class="{'no-padding': filteredCiphers.length}">
|
||||
<div ng-show="!filteredCiphers.length">No items to list.</div>
|
||||
<div class="table-responsive" ng-show="filteredCiphers.length">
|
||||
<table class="table table-striped table-hover table-vmiddle">
|
||||
<tbody>
|
||||
<tr ng-repeat="cipher in collectionCiphers = (ciphers | filter: filterByCollection(collection) |
|
||||
filter: (main.searchVaultText || '') | orderBy: ['name', 'subTitle']) track by cipher.id">
|
||||
<tr ng-repeat="cipher in filteredCiphers = (ciphers | filter: cipherFilter() |
|
||||
filter: (searchVaultText || '') | orderBy: ['name', 'subTitle']) track by cipher.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">
|
||||
@ -61,12 +52,6 @@
|
||||
<i class="fa fa-fw fa-file-text-o"></i> Event Logs
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" stop-click ng-click="removeCipher(cipher, collection)" class="text-red"
|
||||
ng-if="collection.id">
|
||||
<i class="fa fa-fw fa-remove"></i> Remove
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" stop-click ng-click="deleteCipher(cipher)" class="text-red">
|
||||
<i class="fa fa-fw fa-trash"></i> Delete
|
||||
@ -93,3 +78,65 @@
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<aside class="control-sidebar control-sidebar-light">
|
||||
<div class="tab-content">
|
||||
<form class="search-form">
|
||||
<label for="search" class="sr-only">Search</label>
|
||||
<div class="form-group has-feedback">
|
||||
<input type="search" id="search" class="form-control" placeholder="Search org vault..."
|
||||
ng-model="searchVaultText" />
|
||||
<span class="fa fa-search form-control-feedback" aria-hidden="true"></span>
|
||||
</div>
|
||||
</form>
|
||||
<ul class="control-sidebar-menu">
|
||||
<li ng-class="{active: selectedAll}">
|
||||
<a href="#" stop-click ng-click="filterAll()">
|
||||
<i class="fa fa-th fa-fw"></i> All Items
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3 class="control-sidebar-heading">Types</h3>
|
||||
<div class="control-sidebar-section">
|
||||
<ul class="control-sidebar-menu">
|
||||
<li ng-class="{active: constants.cipherType.login === selectedType}">
|
||||
<a href="#" stop-click ng-click="filterType(constants.cipherType.login)">
|
||||
<i class="fa fa-globe fa-fw"></i> Login
|
||||
</a>
|
||||
</li>
|
||||
<li ng-class="{active: constants.cipherType.card === selectedType}">
|
||||
<a href="#" stop-click ng-click="filterType(constants.cipherType.card)">
|
||||
<i class="fa fa-credit-card fa-fw"></i> Card
|
||||
</a>
|
||||
</li>
|
||||
<li ng-class="{active: constants.cipherType.identity === selectedType}">
|
||||
<a href="#" stop-click ng-click="filterType(constants.cipherType.identity)">
|
||||
<i class="fa fa-id-card-o fa-fw"></i> Identity
|
||||
</a>
|
||||
</li>
|
||||
<li ng-class="{active: constants.cipherType.secureNote === selectedType}">
|
||||
<a href="#" stop-click ng-click="filterType(constants.cipherType.secureNote)">
|
||||
<i class="fa fa-sticky-note-o fa-fw"></i> Secure Note
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<h3 class="control-sidebar-heading">Collections</h3>
|
||||
<div ng-show="loading && !collections.length">
|
||||
<p>Loading...</p>
|
||||
</div>
|
||||
<div ng-show="!loading && !collections.length">
|
||||
<p>No collections.</p>
|
||||
</div>
|
||||
<div class="control-sidebar-section" ng-show="!loading && collections.length">
|
||||
<ul class="control-sidebar-menu">
|
||||
<li ng-repeat="collection in collections | orderBy: [collectionSort] track by collection.id"
|
||||
ng-class="{active: selectedCollection && collection.id === selectedCollection.id}">
|
||||
<a href="#" stop-click ng-click="filterCollection(collection)">
|
||||
<i class="fa fa-caret-right fa-fw"></i>
|
||||
{{collection.name}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</aside>
|
||||
|
@ -95,7 +95,7 @@ angular
|
||||
_service.logOut = function () {
|
||||
tokenService.clearTokens();
|
||||
cryptoService.clearKeys();
|
||||
$rootScope.vaultGroupings = $rootScope.vaultCiphers = null;
|
||||
$rootScope.vaultCiphers = $rootScope.vaultFolders = $rootScope.vaultCollections = null;
|
||||
_userProfile = null;
|
||||
};
|
||||
|
||||
|
@ -2,15 +2,16 @@
|
||||
.module('bit.vault')
|
||||
|
||||
.controller('vaultAddCipherController', function ($scope, apiService, $uibModalInstance, cryptoService, cipherService,
|
||||
passwordService, selectedFolder, $analytics, checkedFavorite, $rootScope, authService, $uibModal, constants, $filter) {
|
||||
passwordService, selectedFolder, $analytics, checkedFavorite, $rootScope, authService, $uibModal, constants,
|
||||
$filter, selectedType) {
|
||||
$analytics.eventTrack('vaultAddCipherController', { category: 'Modal' });
|
||||
$scope.folders = $filter('filter')($rootScope.vaultGroupings, { folder: true });
|
||||
$scope.folders = $rootScope.vaultFolders;
|
||||
$scope.constants = constants;
|
||||
$scope.selectedType = constants.cipherType.login.toString();
|
||||
$scope.selectedType = selectedType ? selectedType.toString() : constants.cipherType.login.toString();
|
||||
$scope.cipher = {
|
||||
folderId: selectedFolder ? selectedFolder.id : null,
|
||||
favorite: checkedFavorite === true,
|
||||
type: constants.cipherType.login,
|
||||
type: selectedType || constants.cipherType.login,
|
||||
login: {
|
||||
uris: [{
|
||||
uri: null,
|
||||
|
@ -5,24 +5,27 @@
|
||||
cipherService, $q, $localStorage, $timeout, $rootScope, $state, $analytics, constants, validationService) {
|
||||
$scope.loading = true;
|
||||
$scope.ciphers = [];
|
||||
$scope.folderCount = 0;
|
||||
$scope.collectionCount = 0;
|
||||
$scope.firstCollectionId = null;
|
||||
$scope.folders = [];
|
||||
$scope.collections = [];
|
||||
$scope.constants = constants;
|
||||
$scope.favoriteCollapsed = $localStorage.collapsedFolders && 'favorite' in $localStorage.collapsedFolders;
|
||||
$scope.groupingIdFilter = undefined;
|
||||
$scope.typeFilter = undefined;
|
||||
$scope.filter = undefined;
|
||||
$scope.selectedType = undefined;
|
||||
$scope.selectedFolder = undefined;
|
||||
$scope.selectedCollection = undefined;
|
||||
$scope.selectedFavorites = false;
|
||||
$scope.selectedAll = true;
|
||||
$scope.selectedTitle = 'All';
|
||||
$scope.selectedIcon = 'fa-th';
|
||||
|
||||
if ($state.params.refreshFromServer) {
|
||||
$rootScope.vaultGroupings = $rootScope.vaultCiphers = null;
|
||||
$rootScope.vaultFolders = $rootScope.vaultCollections = $rootScope.vaultCiphers = null;
|
||||
}
|
||||
|
||||
$scope.$on('$viewContentLoaded', function () {
|
||||
$("#search").focus();
|
||||
|
||||
if ($rootScope.vaultGroupings && $rootScope.vaultCiphers) {
|
||||
if (($rootScope.vaultFolders || $rootScope.vaultCollections) && $rootScope.vaultCiphers) {
|
||||
$scope.loading = false;
|
||||
loadGroupingData($rootScope.vaultGroupings);
|
||||
loadCipherData($rootScope.vaultCiphers);
|
||||
return;
|
||||
}
|
||||
@ -31,30 +34,30 @@
|
||||
});
|
||||
|
||||
function loadDataFromServer() {
|
||||
var decGroupings = [{
|
||||
var decFolders = [{
|
||||
id: null,
|
||||
name: 'No Folder',
|
||||
folder: true
|
||||
name: 'No Folder'
|
||||
}];
|
||||
|
||||
var decCollections = [];
|
||||
|
||||
var collectionPromise = apiService.collections.listMe({ writeOnly: false }, function (collections) {
|
||||
for (var i = 0; i < collections.Data.length; i++) {
|
||||
var decCollection = cipherService.decryptCollection(collections.Data[i], null, true);
|
||||
decCollection.collection = true;
|
||||
decGroupings.push(decCollection);
|
||||
decCollections.push(decCollection);
|
||||
}
|
||||
}).$promise;
|
||||
|
||||
var folderPromise = apiService.folders.list({}, function (folders) {
|
||||
for (var i = 0; i < folders.Data.length; i++) {
|
||||
var decFolder = cipherService.decryptFolderPreview(folders.Data[i]);
|
||||
decFolder.folder = true;
|
||||
decGroupings.push(decFolder);
|
||||
decFolders.push(decFolder);
|
||||
}
|
||||
}).$promise;
|
||||
|
||||
var groupingPromise = $q.all([collectionPromise, folderPromise]).then(function () {
|
||||
loadGroupingData(decGroupings);
|
||||
$rootScope.vaultCollections = decCollections;
|
||||
$rootScope.vaultFolders = decFolders;
|
||||
});
|
||||
|
||||
var cipherPromise = apiService.ciphers.list({}, function (ciphers) {
|
||||
@ -75,34 +78,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
function loadGroupingData(decGroupings) {
|
||||
$rootScope.vaultGroupings = $filter('orderBy')(decGroupings, ['folder', groupingSort]);
|
||||
var collections = $filter('filter')($rootScope.vaultGroupings, { collection: true });
|
||||
$scope.collectionCount = collections.length;
|
||||
$scope.folderCount = decGroupings.length - collections.length - 1;
|
||||
if (collections && collections.length) {
|
||||
$scope.firstCollectionId = collections[0].id;
|
||||
}
|
||||
}
|
||||
|
||||
function loadCipherData(decCiphers) {
|
||||
angular.forEach($rootScope.vaultGroupings, function (grouping, groupingIndex) {
|
||||
grouping.collapsed = $localStorage.collapsedFolders &&
|
||||
(grouping.id || 'none') in $localStorage.collapsedFolders;
|
||||
|
||||
angular.forEach(decCiphers, function (cipherValue) {
|
||||
if (cipherValue.favorite) {
|
||||
cipherValue.sort = -1;
|
||||
}
|
||||
else if (grouping.folder && cipherValue.folderId == grouping.id) {
|
||||
cipherValue.sort = groupingIndex;
|
||||
}
|
||||
else if (grouping.collection && cipherValue.collectionIds.indexOf(grouping.id) > -1) {
|
||||
cipherValue.sort = groupingIndex;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$rootScope.vaultCiphers = $scope.ciphers = $filter('orderBy')(decCiphers, ['sort', 'name', 'subTitle']);
|
||||
|
||||
var chunks = chunk($rootScope.vaultCiphers, 400);
|
||||
@ -136,61 +112,19 @@
|
||||
return chunks;
|
||||
}
|
||||
|
||||
function groupingSort(item) {
|
||||
$scope.groupingSort = function (item) {
|
||||
if (!item.id) {
|
||||
return '';
|
||||
}
|
||||
|
||||
return item.name.toLowerCase();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.clipboardError = function (e) {
|
||||
alert('Your web browser does not support easy clipboard copying. ' +
|
||||
'Edit the item and copy it manually instead.');
|
||||
};
|
||||
|
||||
$scope.collapseExpand = function (grouping, favorite) {
|
||||
if (!$localStorage.collapsedFolders) {
|
||||
$localStorage.collapsedFolders = {};
|
||||
}
|
||||
|
||||
var id = favorite ? 'favorite' : (grouping.id || 'none');
|
||||
if (id in $localStorage.collapsedFolders) {
|
||||
delete $localStorage.collapsedFolders[id];
|
||||
}
|
||||
else {
|
||||
$localStorage.collapsedFolders[id] = true;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.collapseAll = function () {
|
||||
if (!$localStorage.collapsedFolders) {
|
||||
$localStorage.collapsedFolders = {};
|
||||
}
|
||||
|
||||
$localStorage.collapsedFolders.none = true;
|
||||
$localStorage.collapsedFolders.favorite = true;
|
||||
|
||||
if ($rootScope.vaultGroupings) {
|
||||
for (var i = 0; i < $rootScope.vaultGroupings.length; i++) {
|
||||
$localStorage.collapsedFolders[$rootScope.vaultGroupings[i].id] = true;
|
||||
}
|
||||
}
|
||||
|
||||
$('.box').addClass('collapsed-box');
|
||||
$('.box .box-header button i.fa-minus').removeClass('fa-minus').addClass('fa-plus');
|
||||
};
|
||||
|
||||
$scope.expandAll = function () {
|
||||
if ($localStorage.collapsedFolders) {
|
||||
delete $localStorage.collapsedFolders;
|
||||
}
|
||||
|
||||
$('.box').removeClass('collapsed-box');
|
||||
$('.box-body').show();
|
||||
$('.box .box-header button i.fa-plus').removeClass('fa-plus').addClass('fa-minus');
|
||||
};
|
||||
|
||||
$scope.editCipher = function (cipher) {
|
||||
var editModel = $uibModal.open({
|
||||
animation: true,
|
||||
@ -225,14 +159,15 @@
|
||||
$scope.addCipher();
|
||||
});
|
||||
|
||||
$scope.addCipher = function (grouping, favorite) {
|
||||
$scope.addCipher = function () {
|
||||
var addModel = $uibModal.open({
|
||||
animation: true,
|
||||
templateUrl: 'app/vault/views/vaultAddCipher.html',
|
||||
controller: 'vaultAddCipherController',
|
||||
resolve: {
|
||||
selectedFolder: function () { return grouping && grouping.folder ? grouping : null; },
|
||||
checkedFavorite: function () { return favorite; }
|
||||
selectedFolder: function () { return $scope.selectedFolder; },
|
||||
selectedType: function () { return $scope.selectedType; },
|
||||
checkedFavorite: function () { return $scope.selectedFavorites; }
|
||||
}
|
||||
});
|
||||
|
||||
@ -332,36 +267,26 @@
|
||||
});
|
||||
|
||||
addModel.result.then(function (addedFolder) {
|
||||
addedFolder.folder = true;
|
||||
$rootScope.vaultGroupings.push(addedFolder);
|
||||
loadGroupingData($rootScope.vaultGroupings);
|
||||
$rootScope.vaultFolders.push(addedFolder);
|
||||
});
|
||||
};
|
||||
|
||||
$scope.deleteFolder = function (folder) {
|
||||
if (!confirm('Are you sure you want to delete this folder (' + folder.name + ')?')) {
|
||||
if (!confirm('Are you sure you want to delete this folder (' + folder.name + ')? ' +
|
||||
'Any items will be moved to "No Folder".')) {
|
||||
return;
|
||||
}
|
||||
|
||||
apiService.folders.del({ id: folder.id }, function () {
|
||||
$analytics.eventTrack('Deleted Folder');
|
||||
var index = $rootScope.vaultGroupings.indexOf(folder);
|
||||
var index = $rootScope.vaultFolders.indexOf(folder);
|
||||
if (index > -1) {
|
||||
$rootScope.vaultGroupings.splice(index, 1);
|
||||
$scope.folderCount--;
|
||||
$rootScope.vaultFolders.splice(index, 1);
|
||||
$scope.filterAll();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$scope.canDeleteFolder = function (folder) {
|
||||
if (!folder || !folder.id || !$rootScope.vaultCiphers) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var ciphers = $filter('filter')($rootScope.vaultCiphers, { folderId: folder.id });
|
||||
return ciphers && ciphers.length === 0;
|
||||
};
|
||||
|
||||
$scope.share = function (cipher) {
|
||||
var modal = $uibModal.open({
|
||||
animation: true,
|
||||
@ -397,52 +322,94 @@
|
||||
});
|
||||
};
|
||||
|
||||
$scope.filterGrouping = function (grouping) {
|
||||
$scope.groupingIdFilter = grouping.id;
|
||||
$scope.filterCollection = function (col) {
|
||||
resetSelected();
|
||||
$scope.selectedCollection = col;
|
||||
$scope.selectedIcon = 'fa-cube';
|
||||
$scope.filter = function (c) {
|
||||
return c.collectionIds && c.collectionIds.indexOf(col.id) > -1;
|
||||
};
|
||||
fixLayout();
|
||||
};
|
||||
|
||||
$scope.filterFolder = function (f) {
|
||||
resetSelected();
|
||||
$scope.selectedFolder = f;
|
||||
$scope.selectedIcon = 'fa-folder-open' + (!f.id ? '-o' : '');
|
||||
$scope.filter = function (c) {
|
||||
return c.folderId === f.id;
|
||||
};
|
||||
fixLayout();
|
||||
};
|
||||
|
||||
$scope.filterType = function (t) {
|
||||
resetSelected();
|
||||
$scope.selectedType = t;
|
||||
switch (t) {
|
||||
case constants.cipherType.login:
|
||||
$scope.selectedTitle = 'Login';
|
||||
$scope.selectedIcon = 'fa-globe';
|
||||
break;
|
||||
case constants.cipherType.card:
|
||||
$scope.selectedTitle = 'Card';
|
||||
$scope.selectedIcon = 'fa-credit-card';
|
||||
break;
|
||||
case constants.cipherType.identity:
|
||||
$scope.selectedTitle = 'Identity';
|
||||
$scope.selectedIcon = 'fa-id-card-o';
|
||||
break;
|
||||
case constants.cipherType.secureNote:
|
||||
$scope.selectedTitle = 'Secure Note';
|
||||
$scope.selectedIcon = 'fa-sticky-note-o';
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
$scope.filter = function (c) {
|
||||
return c.type === t;
|
||||
};
|
||||
fixLayout();
|
||||
};
|
||||
|
||||
$scope.filterFavorites = function () {
|
||||
resetSelected();
|
||||
$scope.selectedFavorites = true;
|
||||
$scope.selectedTitle = 'Favorites';
|
||||
$scope.selectedIcon = 'fa-star';
|
||||
$scope.filter = function (c) {
|
||||
return !!c.favorite;
|
||||
};
|
||||
fixLayout();
|
||||
};
|
||||
|
||||
$scope.filterAll = function () {
|
||||
resetSelected();
|
||||
$scope.selectedAll = true;
|
||||
$scope.selectedTitle = 'All';
|
||||
$scope.selectedIcon = 'fa-th';
|
||||
$scope.filter = null;
|
||||
fixLayout();
|
||||
};
|
||||
|
||||
function resetSelected() {
|
||||
$scope.selectedFolder = undefined;
|
||||
$scope.selectedCollection = undefined;
|
||||
$scope.selectedType = undefined;
|
||||
$scope.selectedFavorites = false;
|
||||
$scope.selectedAll = false;
|
||||
}
|
||||
|
||||
function fixLayout() {
|
||||
if ($.AdminLTE && $.AdminLTE.layout) {
|
||||
$timeout(function () {
|
||||
$.AdminLTE.layout.fix();
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
$scope.filterType = function (type) {
|
||||
$scope.typeFilter = type;
|
||||
|
||||
if ($.AdminLTE && $.AdminLTE.layout) {
|
||||
$timeout(function () {
|
||||
$.AdminLTE.layout.fix();
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.clearFilters = function () {
|
||||
$scope.groupingIdFilter = undefined;
|
||||
$scope.typeFilter = undefined;
|
||||
|
||||
if ($.AdminLTE && $.AdminLTE.layout) {
|
||||
$timeout(function () {
|
||||
$.AdminLTE.layout.fix();
|
||||
}, 0);
|
||||
}
|
||||
};
|
||||
|
||||
$scope.groupingFilter = function (grouping) {
|
||||
return $scope.groupingIdFilter === undefined || grouping.id === $scope.groupingIdFilter;
|
||||
};
|
||||
|
||||
$scope.cipherFilter = function (grouping) {
|
||||
$scope.cipherFilter = function () {
|
||||
return function (cipher) {
|
||||
var matchesGrouping = grouping === null;
|
||||
if (!matchesGrouping && grouping.folder && cipher.folderId === grouping.id) {
|
||||
matchesGrouping = true;
|
||||
}
|
||||
else if (!matchesGrouping && grouping.collection && cipher.collectionIds.indexOf(grouping.id) > -1) {
|
||||
matchesGrouping = true;
|
||||
}
|
||||
|
||||
return matchesGrouping && ($scope.typeFilter === undefined || cipher.type === $scope.typeFilter);
|
||||
return !$scope.filter || $scope.filter(cipher);
|
||||
};
|
||||
};
|
||||
|
||||
@ -450,14 +417,8 @@
|
||||
selectAll(false);
|
||||
};
|
||||
|
||||
$scope.selectFolder = function (folder, $event) {
|
||||
var checkbox = $($event.currentTarget).closest('.box').find('input[name="cipherSelection"]');
|
||||
checkbox.prop('checked', true);
|
||||
};
|
||||
|
||||
$scope.select = function ($event) {
|
||||
var checkbox = $($event.currentTarget).closest('tr').find('input[name="cipherSelection"]');
|
||||
checkbox.prop('checked', !checkbox.prop('checked'));
|
||||
$scope.selectAll = function () {
|
||||
selectAll(true);
|
||||
};
|
||||
|
||||
function distinct(value, index, self) {
|
||||
|
@ -4,7 +4,7 @@
|
||||
.controller('vaultEditCipherController', function ($scope, apiService, $uibModalInstance, cryptoService, cipherService,
|
||||
passwordService, cipherId, $analytics, $rootScope, authService, $uibModal, constants, $filter) {
|
||||
$analytics.eventTrack('vaultEditCipherController', { category: 'Modal' });
|
||||
$scope.folders = $filter('filter')($rootScope.vaultGroupings, { folder: true });
|
||||
$scope.folders = $rootScope.vaultFolders;
|
||||
$scope.cipher = {};
|
||||
$scope.readOnly = false;
|
||||
$scope.constants = constants;
|
||||
|
@ -4,7 +4,7 @@
|
||||
.controller('vaultMoveCiphersController', function ($scope, apiService, $uibModalInstance, ids, $analytics,
|
||||
$rootScope, $filter) {
|
||||
$analytics.eventTrack('vaultMoveCiphersController', { category: 'Modal' });
|
||||
$scope.folders = $filter('filter')($rootScope.vaultGroupings, { folder: true });
|
||||
$scope.folders = $rootScope.vaultFolders;
|
||||
$scope.count = ids.length;
|
||||
|
||||
$scope.save = function () {
|
||||
|
@ -16,19 +16,14 @@
|
||||
</a>
|
||||
</li>
|
||||
<li role="separator" class="divider"></li>
|
||||
<li>
|
||||
<a href="#" stop-click ng-click="selectAll()">
|
||||
<i class="fa fa-fw fa-check-square-o"></i> Select All
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" stop-click ng-click="unselectAll()">
|
||||
<i class="fa fa-fw fa-minus-circle"></i> Unselect All
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" stop-click ng-click="collapseAll()">
|
||||
<i class="fa fa-fw fa-minus-square-o"></i> Collapse All
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" stop-click ng-click="expandAll()">
|
||||
<i class="fa fa-fw fa-plus-square-o"></i> Expand All
|
||||
<i class="fa fa-fw fa-minus-square-o"></i> Unselect All
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@ -36,184 +31,57 @@
|
||||
<h1>
|
||||
My Vault
|
||||
<small class="visible-md-inline visible-lg-inline">
|
||||
<span ng-pluralize count="folderCount" when="{'1': '{} folder', 'other': '{} folders'}"></span>,
|
||||
<span ng-pluralize count="collectionCount" when="{'1': '{} collection', 'other': '{} collections'}"></span>, &
|
||||
<span ng-pluralize count="vaultFolders.length > 0 ? vaultFolders.length - 1 : 0"
|
||||
when="{'1': '{} folder', 'other': '{} folders'}"></span>,
|
||||
<span ng-pluralize count="vaultCollections.length"
|
||||
when="{'1': '{} collection', 'other': '{} collections'}"></span>, &
|
||||
<span ng-pluralize count="ciphers.length" when="{'1': '{} item', 'other': '{} items'}"></span>
|
||||
</small>
|
||||
</h1>
|
||||
</section>
|
||||
<section class="content">
|
||||
<div ng-show="loading && !vaultGroupings.length">
|
||||
<div ng-show="loading">
|
||||
<p>Loading...</p>
|
||||
</div>
|
||||
<div class="box box-primary" ng-class="{'collapsed-box': favoriteCollapsed}" style="margin-bottom: 40px;"
|
||||
ng-show="vaultGroupings.length && groupingIdFilter === undefined && (!main.searchVaultText || favoriteCiphers.length)">
|
||||
<div class="box" ng-show="!loading">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
<i class="fa fa-star"></i>
|
||||
Favorites
|
||||
<small ng-pluralize count="favoriteCiphers.length" when="{'1': '{} item', 'other': '{} items'}"></small>
|
||||
<i class="fa {{selectedIcon}}"></i>
|
||||
{{selectedFolder ? selectedFolder.name : selectedCollection ? selectedCollection.name : selectedTitle}}
|
||||
<small ng-pluralize count="filteredCiphers.length" when="{'1': '{} item', 'other': '{} items'}"></small>
|
||||
</h3>
|
||||
<div class="box-tools">
|
||||
<div class="box-tools" ng-if="selectedFolder">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-box-tool dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="fa fa-cog"></i> <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-right">
|
||||
<li>
|
||||
<a href="#" stop-click ng-click="addCipher(null, true)">
|
||||
<i class="fa fa-fw fa-plus-circle"></i> New Item
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse" title="Collapse/Expand"
|
||||
ng-click="collapseExpand(null, true)">
|
||||
<i class="fa" ng-class="{'fa-minus': !favoriteCollapsed, 'fa-plus': favoriteCollapsed}"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body" ng-class="{'no-padding': favoriteCiphers.length}">
|
||||
<div ng-show="!favoriteCiphers.length">
|
||||
<p>No favorite items.</p>
|
||||
<button type="button" ng-click="addCipher(null, true)" class="btn btn-default btn-flat">Add an Item</button>
|
||||
</div>
|
||||
<div class="table-responsive" ng-show="favoriteCiphers.length">
|
||||
<table class="table table-striped table-hover table-vmiddle">
|
||||
<tbody>
|
||||
<tr ng-repeat="cipher in favoriteCiphers = (ciphers | filter: { favorite: true } |
|
||||
filter: cipherFilter(null) | filter: (main.searchVaultText || '')) track by cipher.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">
|
||||
<i class="fa fa-cog"></i> <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li>
|
||||
<a href="#" stop-click ng-click="editCipher(cipher)">
|
||||
<i class="fa fa-fw fa-pencil"></i> Edit
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" stop-click ng-click="attachments(cipher)">
|
||||
<i class="fa fa-fw fa-paperclip"></i> Attachments
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="!cipher.organizationId">
|
||||
<a href="#" stop-click ng-click="share(cipher)">
|
||||
<i class="fa fa-fw fa-share-alt"></i> Share
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="cipher.organizationId && cipher.edit">
|
||||
<a href="#" stop-click ng-click="editCollections(cipher)">
|
||||
<i class="fa fa-fw fa-cubes"></i> Collections
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="cipher.meta.password">
|
||||
<a href="#" stop-click ngclipboard ngclipboard-error="clipboardError(e)"
|
||||
data-clipboard-text="{{cipher.meta.password}}">
|
||||
<i class="fa fa-fw fa-clipboard"></i> Copy Password
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="cipher.edit">
|
||||
<a href="#" stop-click ng-click="deleteCipher(cipher)" class="text-red">
|
||||
<i class="fa fa-fw fa-trash"></i> Delete
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</td>
|
||||
<td class="action-select" ng-click="select($event)">
|
||||
<input type="checkbox" value="{{::cipher.id}}" name="cipherSelection" stop-prop />
|
||||
</td>
|
||||
<td class="vault-icon" ng-click="select($event)">
|
||||
<i class="fa fa-fw fa-lg {{::cipher.icon}}" ng-if="!cipher.meta.image"></i>
|
||||
<img alt="" ng-if="cipher.meta.image" ng-src="{{cipher.meta.image}}"
|
||||
fallback-src="images/fa-globe.png" />
|
||||
</td>
|
||||
<td ng-click="select($event)">
|
||||
<a href="#" stop-click ng-click="editCipher(cipher)" stop-prop>{{cipher.name}}</a>
|
||||
<i class="fa fa-share-alt text-muted" title="Shared" ng-if="cipher.organizationId"
|
||||
stop-prop></i>
|
||||
<i class="fa fa-paperclip text-muted" title="Attachments" ng-if="cipher.hasAttachments"
|
||||
stop-prop></i><br />
|
||||
<span class="text-sm text-muted" stop-prop>{{cipher.subTitle}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box" ng-class="{'collapsed-box': grouping.collapsed}"
|
||||
ng-repeat="grouping in filteredVaultGroupings = (vaultGroupings | filter: groupingFilter) track by grouping.id"
|
||||
ng-show="vaultGroupings.length && (!main.searchVaultText || groupingCiphers.length)"
|
||||
ng-style="firstCollectionId && grouping.id === firstCollectionId &&
|
||||
groupingIdFilter !== grouping.id && {'margin-top': '40px'}">
|
||||
<div class="box-header with-border">
|
||||
<h3 class="box-title">
|
||||
<i class="fa" ng-if="grouping.folder"
|
||||
ng-class="{'fa-folder-open': grouping.id !== null, 'fa-folder-open-o': grouping.id === null}"></i>
|
||||
<i class="fa fa-cube" ng-if="grouping.collection"></i>
|
||||
{{grouping.name}}
|
||||
<small ng-pluralize count="groupingCiphers.length" when="{'1': '{} item', 'other': '{} items'}"></small>
|
||||
</h3>
|
||||
<div class="box-tools">
|
||||
<div class="btn-group">
|
||||
<button type="button" class="btn btn-box-tool dropdown-toggle" data-toggle="dropdown">
|
||||
<i class="fa fa-cog"></i> <span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu dropdown-menu-right" ng-if="grouping.folder">
|
||||
<li>
|
||||
<a href="#" stop-click ng-click="addCipher(grouping)">
|
||||
<i class="fa fa-fw fa-plus-circle"></i> New Item
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="grouping.id">
|
||||
<a href="#" stop-click ng-click="editFolder(grouping)">
|
||||
<a href="#" stop-click ng-click="editFolder(selectedFolder)">
|
||||
<i class="fa fa-fw fa-pencil"></i> Edit Folder
|
||||
</a>
|
||||
</li>
|
||||
<li ng-show="canDeleteFolder(grouping)">
|
||||
<a href="#" stop-click ng-click="deleteFolder(grouping)" class="text-red">
|
||||
<li>
|
||||
<a href="#" stop-click ng-click="deleteFolder(selectedFolder)" class="text-red">
|
||||
<i class="fa fa-fw fa-trash"></i> Delete Folder
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#" stop-click ng-click="selectFolder(grouping, $event)">
|
||||
<i class="fa fa-fw fa-check-square-o"></i> Select All
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul class="dropdown-menu dropdown-menu-right" ng-if="grouping.collection">
|
||||
<li>
|
||||
<a href="#" stop-click ng-click="selectFolder(grouping, $event)">
|
||||
<i class="fa fa-fw fa-check-square-o"></i> Select All
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<button type="button" class="btn btn-box-tool" data-widget="collapse" title="Collapse/Expand"
|
||||
ng-click="collapseExpand(grouping)">
|
||||
<i class="fa" ng-class="{'fa-minus': !grouping.collapsed, 'fa-plus': grouping.collapsed}"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-body" ng-class="{'no-padding': groupingCiphers.length}">
|
||||
<div ng-show="!groupingCiphers.length">
|
||||
<div ng-if="grouping.folder">
|
||||
<p>No items in this folder.</p>
|
||||
<button type="button" ng-click="addCipher(grouping)" class="btn btn-default btn-flat">Add an Item</button>
|
||||
</div>
|
||||
<div ng-if="!grouping.folder">
|
||||
<p>No items in this collection.</p>
|
||||
</div>
|
||||
<div class="box-body" ng-class="{'no-padding': filteredCiphers.length}">
|
||||
<div ng-show="!filteredCiphers.length">
|
||||
<p>No items to list.</p>
|
||||
<button type="button" ng-click="addCipher()" class="btn btn-default btn-flat">
|
||||
Add an Item
|
||||
</button>
|
||||
</div>
|
||||
<div class="table-responsive" ng-show="groupingCiphers.length">
|
||||
<div class="table-responsive" ng-show="filteredCiphers.length">
|
||||
<table class="table table-striped table-hover table-vmiddle">
|
||||
<tbody>
|
||||
<tr ng-repeat="cipher in groupingCiphers = (ciphers | filter: cipherFilter(grouping) |
|
||||
filter: (main.searchVaultText || '')) track by cipher.id">
|
||||
<tr ng-repeat="cipher in filteredCiphers = (ciphers | filter: cipherFilter() |
|
||||
filter: (searchVaultText || '')) track by cipher.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">
|
||||
@ -281,80 +149,82 @@
|
||||
</section>
|
||||
<aside class="control-sidebar control-sidebar-light">
|
||||
<div class="tab-content">
|
||||
<form class="search-form">
|
||||
<label for="search" class="sr-only">Search</label>
|
||||
<div class="form-group has-feedback">
|
||||
<input type="search" id="search" class="form-control" placeholder="Search my vault..."
|
||||
ng-model="searchVaultText" />
|
||||
<span class="fa fa-search form-control-feedback" aria-hidden="true"></span>
|
||||
</div>
|
||||
</form>
|
||||
<ul class="control-sidebar-menu">
|
||||
<li>
|
||||
<a href="#" stop-click ng-click="clearFilters()">
|
||||
Clear All Filters
|
||||
<li ng-class="{active: selectedAll}">
|
||||
<a href="#" stop-click ng-click="filterAll()">
|
||||
<i class="fa fa-th fa-fw"></i> All Items
|
||||
</a>
|
||||
</li>
|
||||
<li ng-class="{active: selectedFavorites}">
|
||||
<a href="#" stop-click ng-click="filterFavorites()">
|
||||
<i class="fa fa-star fa-fw"></i> Favorites
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
<h3 class="control-sidebar-heading">
|
||||
<i class="fa fa-tag fa-fw"></i> Types
|
||||
</h3>
|
||||
<h3 class="control-sidebar-heading">Types</h3>
|
||||
<div class="control-sidebar-section">
|
||||
<ul class="control-sidebar-menu">
|
||||
<li>
|
||||
<li ng-class="{active: constants.cipherType.login === selectedType}">
|
||||
<a href="#" stop-click ng-click="filterType(constants.cipherType.login)">
|
||||
<i class="fa fa-check fa-fw" ng-if="constants.cipherType.login === typeFilter"></i>
|
||||
<i class="fa fa-globe fa-fw" ng-if="constants.cipherType.login !== typeFilter"></i> Login
|
||||
<i class="fa fa-globe fa-fw"></i> Login
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<li ng-class="{active: constants.cipherType.card === selectedType}">
|
||||
<a href="#" stop-click ng-click="filterType(constants.cipherType.card)">
|
||||
<i class="fa fa-check fa-fw" ng-if="constants.cipherType.card === typeFilter"></i>
|
||||
<i class="fa fa-credit-card fa-fw" ng-if="constants.cipherType.card !== typeFilter"></i> Card
|
||||
<i class="fa fa-credit-card fa-fw"></i> Card
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<li ng-class="{active: constants.cipherType.identity === selectedType}">
|
||||
<a href="#" stop-click ng-click="filterType(constants.cipherType.identity)">
|
||||
<i class="fa fa-check fa-fw" ng-if="constants.cipherType.identity === typeFilter"></i>
|
||||
<i class="fa fa-id-card-o fa-fw" ng-if="constants.cipherType.identity !== typeFilter"></i> Identity
|
||||
<i class="fa fa-id-card-o fa-fw"></i> Identity
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<li ng-class="{active: constants.cipherType.secureNote === selectedType}">
|
||||
<a href="#" stop-click ng-click="filterType(constants.cipherType.secureNote)">
|
||||
<i class="fa fa-check fa-fw" ng-if="constants.cipherType.secureNote === typeFilter"></i>
|
||||
<i class="fa fa-sticky-note-o fa-fw" ng-if="constants.cipherType.secureNote !== typeFilter"></i> Secure Note
|
||||
<i class="fa fa-sticky-note-o fa-fw"></i> Secure Note
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<h3 class="control-sidebar-heading">
|
||||
<i class="fa fa-folder fa-fw"></i> Folders
|
||||
</h3>
|
||||
<div ng-show="loading && !vaultGroupings.length">
|
||||
<h3 class="control-sidebar-heading">Folders</h3>
|
||||
<div ng-show="loading && !vaultFolders.length">
|
||||
<p>Loading...</p>
|
||||
</div>
|
||||
<div class="control-sidebar-section">
|
||||
<ul class="control-sidebar-menu" ng-show="!loading && folders.length">
|
||||
<li ng-repeat="folder in folders = (vaultGroupings | filter: {folder: true}) track by folder.id">
|
||||
<a href="#" stop-click ng-click="filterGrouping(folder)">
|
||||
<i class="fa fa-check fa-fw" ng-if="folder.id === groupingIdFilter"></i>
|
||||
<i class="fa fa-caret-right fa-fw" ng-if="folder.id !== groupingIdFilter"></i>
|
||||
<div class="control-sidebar-section" ng-show="!loading && vaultFolders.length">
|
||||
<ul class="control-sidebar-menu">
|
||||
<li ng-repeat="folder in vaultFolders | orderBy: [groupingSort] track by folder.id"
|
||||
ng-class="{active: selectedFolder && folder.id === selectedFolder.id}">
|
||||
<a href="#" stop-click ng-click="filterFolder(folder)">
|
||||
<i class="fa fa-caret-right fa-fw"></i>
|
||||
{{folder.name}}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<h3 class="control-sidebar-heading">
|
||||
<i class="fa fa-cubes fa-fw"></i> Collections
|
||||
</h3>
|
||||
<div ng-show="loading && !vaultGroupings.length">
|
||||
<h3 class="control-sidebar-heading">Collections</h3>
|
||||
<div ng-show="loading && !vaultCollections.length">
|
||||
<p>Loading...</p>
|
||||
</div>
|
||||
<div ng-show="!loading && !collections.length">
|
||||
<div ng-show="!loading && !vaultCollections.length">
|
||||
<p>No collections are being shared with you. <i class="fa fa-frown-o"></i></p>
|
||||
<a ui-sref="backend.user.settingsCreateOrg" class="btn btn-default btn-lint">
|
||||
Create an Organization
|
||||
</a>
|
||||
</div>
|
||||
<div class="control-sidebar-section">
|
||||
<ul class="control-sidebar-menu" ng-show="!loading && collections.length">
|
||||
<li ng-repeat="collection in collections =
|
||||
(vaultGroupings | filter: {collection: true}) track by collection.id">
|
||||
<a href="#" stop-click ng-click="filterGrouping(collection)">
|
||||
<i class="fa fa-check fa-fw" ng-if="collection.id === groupingIdFilter"></i>
|
||||
<i class="fa fa-caret-right fa-fw" ng-if="collection.id !== groupingIdFilter"></i>
|
||||
<div class="control-sidebar-section" ng-show="!loading && vaultCollections.length">
|
||||
<ul class="control-sidebar-menu">
|
||||
<li ng-repeat="collection in vaultCollections | orderBy: [groupingSort] track by collection.id"
|
||||
ng-class="{active: selectedCollection && collection.id === selectedCollection}">
|
||||
<a href="#" stop-click ng-click="filterCollection(collection)">
|
||||
<i class="fa fa-caret-right fa-fw"></i>
|
||||
{{collection.name}}
|
||||
</a>
|
||||
</li>
|
||||
|
@ -126,7 +126,7 @@
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="form-group">
|
||||
<label for="uri_match_{{$index}}">Auto-fill Detection</label>
|
||||
<label for="uri_match_{{$index}}">Match Detection</label>
|
||||
<select id="uri_match_{{$index}}" name="Login.Uris[{{$index}}].Match"
|
||||
class="form-control" ng-model="u.matchValue" ng-change="uriMatchChanged(u)">
|
||||
<option value="">Default</option>
|
||||
|
@ -119,7 +119,7 @@
|
||||
</div>
|
||||
<div class="col-sm-4">
|
||||
<div class="form-group">
|
||||
<label for="uri_match_{{$index}}">Auto-fill Detection</label>
|
||||
<label for="uri_match_{{$index}}">Match Detection</label>
|
||||
<select id="uri_match_{{$index}}" name="Login.Uris[{{$index}}].Match" ng-disabled="readOnly"
|
||||
class="form-control" ng-model="u.matchValue" ng-change="uriMatchChanged(u)">
|
||||
<option value="">Default</option>
|
||||
|
@ -32,14 +32,6 @@
|
||||
<a ui-sref="backend.user.vault"><i class="fa fa-arrow-left"></i> Return to my vault</a>
|
||||
</div>
|
||||
</div>
|
||||
<form class="sidebar-form">
|
||||
<label for="search" class="sr-only">Search</label>
|
||||
<div class="form-group has-feedback">
|
||||
<input type="text" id="search" class="form-control" placeholder="Search org. vault..."
|
||||
ng-focus="searchOrganizationVault()" ng-model="main.searchVaultText" />
|
||||
<span class="fa fa-search form-control-feedback" aria-hidden="true"></span>
|
||||
</div>
|
||||
</form>
|
||||
<ul class="sidebar-menu">
|
||||
<li class="header">MY ORGANIZATION</li>
|
||||
<li ng-class="{active: $state.is('backend.org.dashboard')}">
|
||||
|
@ -32,14 +32,6 @@
|
||||
<a ui-sref="frontend.logout">Log Out</a>
|
||||
</div>
|
||||
</div>
|
||||
<form class="sidebar-form">
|
||||
<label for="search" class="sr-only">Search</label>
|
||||
<div class="form-group has-feedback">
|
||||
<input type="text" id="search" class="form-control" placeholder="Search my vault..."
|
||||
ng-focus="searchVault()" ng-model="main.searchVaultText" />
|
||||
<span class="fa fa-search form-control-feedback" aria-hidden="true"></span>
|
||||
</div>
|
||||
</form>
|
||||
<ul class="sidebar-menu">
|
||||
<li class="header">WEB VAULT</li>
|
||||
<li class="treeview" ng-class="{active: $state.includes('backend.user.vault')}">
|
||||
|
@ -153,7 +153,6 @@
|
||||
<script src="app/global/mainController.js"></script>
|
||||
<script src="app/global/topNavController.js"></script>
|
||||
<script src="app/global/sideNavController.js"></script>
|
||||
<script src="app/global/appsController.js"></script>
|
||||
<script src="app/global/premiumRequiredController.js"></script>
|
||||
<script src="app/global/paidOrgRequiredController.js"></script>
|
||||
|
||||
|
@ -152,7 +152,14 @@ body.skin-blue {
|
||||
|
||||
.control-sidebar-heading {
|
||||
padding: 0;
|
||||
margin: 10px 0 10px 0;
|
||||
margin: 15px 0 10px 0;
|
||||
text-transform: uppercase;
|
||||
font-size: @font-size-base;
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.control-sidebar-light .control-sidebar-heading {
|
||||
color: @text-muted;
|
||||
}
|
||||
|
||||
.control-sidebar-menu {
|
||||
@ -160,10 +167,11 @@ body.skin-blue {
|
||||
padding-top: 5px;
|
||||
padding-bottom: 5px;
|
||||
white-space: nowrap;
|
||||
color: @text-color;
|
||||
}
|
||||
|
||||
li.active a {
|
||||
background-color: @component-active-bg;
|
||||
li.active a, li.active a:hover {
|
||||
background-color: lighten(@gray-lte, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
@ -172,6 +180,8 @@ body.skin-blue {
|
||||
overflow-y: auto;
|
||||
padding-right: 15px;
|
||||
margin-right: -15px;
|
||||
padding-left: 15px;
|
||||
margin-left: -15px;
|
||||
}
|
||||
|
||||
.control-sidebar-open {
|
||||
|
Loading…
Reference in New Issue
Block a user