mirror of
https://github.com/bitwarden/desktop.git
synced 2024-11-17 10:45:41 +01:00
converting logins to ciphers on vault lists
This commit is contained in:
parent
355a58f67c
commit
884bce4ec4
@ -72,7 +72,7 @@
|
||||
};
|
||||
|
||||
_service.logOut = function (callback) {
|
||||
$rootScope.vaultLogins = null;
|
||||
$rootScope.vaultCiphers = null;
|
||||
$rootScope.vaultFolders = null;
|
||||
callback();
|
||||
};
|
||||
|
@ -22,8 +22,8 @@
|
||||
|
||||
var delayLoad = true;
|
||||
$scope.loaded = true;
|
||||
if (!$rootScope.vaultLogins) {
|
||||
$rootScope.vaultLogins = [];
|
||||
if (!$rootScope.vaultCiphers) {
|
||||
$rootScope.vaultCiphers = [];
|
||||
delayLoad = false;
|
||||
}
|
||||
if (!$rootScope.vaultFolders) {
|
||||
@ -42,32 +42,30 @@
|
||||
|
||||
function loadVault() {
|
||||
var decFolders = [];
|
||||
var decLogins = [];
|
||||
var decCiphers = [];
|
||||
var promises = [];
|
||||
|
||||
var folderPromise = $q.when(folderService.getAllDecrypted());
|
||||
folderPromise.then(function (folders) {
|
||||
var folderPromise = folderService.getAllDecrypted().then(function (folders) {
|
||||
decFolders = folders;
|
||||
});
|
||||
promises.push(folderPromise);
|
||||
|
||||
var cipherPromise = loginService.getAllDecrypted();
|
||||
cipherPromise.then(function (ciphers) {
|
||||
decLogins = ciphers;
|
||||
var cipherPromise = loginService.getAllDecrypted().then(function (ciphers) {
|
||||
decCiphers = ciphers;
|
||||
});
|
||||
promises.push(cipherPromise);
|
||||
|
||||
$q.all(promises).then(function () {
|
||||
$scope.loaded = true;
|
||||
$rootScope.vaultFolders = decFolders;
|
||||
$rootScope.vaultLogins = decLogins;
|
||||
$rootScope.vaultCiphers = decCiphers;
|
||||
|
||||
if ($scope.showFolderCounts) {
|
||||
// compute item count for each folder
|
||||
for (var i = 0; i < decFolders.length; i++) {
|
||||
var itemCount = 0;
|
||||
for (var j = 0; j < decLogins.length; j++) {
|
||||
if (decLogins[j].folderId === decFolders[i].id) {
|
||||
for (var j = 0; j < decCiphers.length; j++) {
|
||||
if (decCiphers[j].folderId === decFolders[i].id) {
|
||||
itemCount++;
|
||||
}
|
||||
}
|
||||
@ -95,30 +93,30 @@
|
||||
return item.name.toLowerCase();
|
||||
};
|
||||
|
||||
$scope.searchLogins = function () {
|
||||
$scope.searchCiphers = function () {
|
||||
if (!$scope.searchText || $scope.searchText.length < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
return searchLogin;
|
||||
return searchCipher;
|
||||
};
|
||||
|
||||
function searchLogin(login) {
|
||||
function searchCipher(cipher) {
|
||||
var searchTerm = $scope.searchText.toLowerCase();
|
||||
if (login.name && login.name.toLowerCase().indexOf(searchTerm) !== -1) {
|
||||
if (cipher.name && cipher.name.toLowerCase().indexOf(searchTerm) !== -1) {
|
||||
return true;
|
||||
}
|
||||
if (login.username && login.username.toLowerCase().indexOf(searchTerm) !== -1) {
|
||||
if (cipher.username && cipher.username.toLowerCase().indexOf(searchTerm) !== -1) {
|
||||
return true;
|
||||
}
|
||||
if (login.uri && login.uri.toLowerCase().indexOf(searchTerm) !== -1) {
|
||||
if (cipher.login && cipher.login.uri && cipher.login.uri.toLowerCase().indexOf(searchTerm) !== -1) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$scope.addLogin = function () {
|
||||
$scope.addCipher = function () {
|
||||
storeState();
|
||||
$state.go('addLogin', {
|
||||
animation: 'in-slide-up',
|
||||
@ -126,32 +124,32 @@
|
||||
});
|
||||
};
|
||||
|
||||
$scope.viewLogin = function (login) {
|
||||
if (login.clicked) {
|
||||
login.cancelClick = true;
|
||||
$scope.launchWebsite(login);
|
||||
$scope.viewCipher = function (cipher) {
|
||||
if (cipher.clicked) {
|
||||
cipher.cancelClick = true;
|
||||
$scope.launchWebsite(cipher);
|
||||
return;
|
||||
}
|
||||
|
||||
login.clicked = true;
|
||||
cipher.clicked = true;
|
||||
|
||||
$timeout(function () {
|
||||
if (login.cancelClick) {
|
||||
login.cancelClick = false;
|
||||
login.clicked = false;
|
||||
if (cipher.cancelClick) {
|
||||
cipher.cancelClick = false;
|
||||
cipher.clicked = false;
|
||||
return;
|
||||
}
|
||||
|
||||
storeState();
|
||||
$state.go('viewLogin', {
|
||||
loginId: login.id,
|
||||
loginId: cipher.id,
|
||||
animation: 'in-slide-up',
|
||||
from: 'vault'
|
||||
});
|
||||
|
||||
// clean up
|
||||
login.cancelClick = false;
|
||||
login.clicked = false;
|
||||
cipher.cancelClick = false;
|
||||
cipher.clicked = false;
|
||||
}, 200);
|
||||
};
|
||||
|
||||
@ -173,11 +171,11 @@
|
||||
toastr.info(type + i18nService.valueCopied);
|
||||
};
|
||||
|
||||
$scope.launchWebsite = function (login) {
|
||||
$scope.launchWebsite = function (cipher) {
|
||||
$timeout(function () {
|
||||
if (login.uri.startsWith('http://') || login.uri.startsWith('https://')) {
|
||||
if (cipher.uri.startsWith('http://') || cipher.uri.startsWith('https://')) {
|
||||
$analytics.eventTrack('Launched Website From Listing');
|
||||
chrome.tabs.create({ url: login.uri });
|
||||
chrome.tabs.create({ url: cipher.uri });
|
||||
if (utilsService.inPopup($window)) {
|
||||
$window.close();
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
var pageSize = 100,
|
||||
decFolder = null,
|
||||
decLogins = [];
|
||||
decCiphers = [];
|
||||
|
||||
$scope.folder = {
|
||||
id: !state.folderId || state.folderId === '0' ? null : state.folderId,
|
||||
@ -20,8 +20,8 @@
|
||||
$('#search').focus();
|
||||
|
||||
$scope.loaded = false;
|
||||
$scope.vaultLogins = [];
|
||||
$scope.pagedVaultLogins = [];
|
||||
$scope.vaultCiphers = [];
|
||||
$scope.pagedVaultCiphers = [];
|
||||
$scope.searchText = null;
|
||||
loadVault();
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
if ($scope.folder.id) {
|
||||
var folderDeferred = $q.defer();
|
||||
folderService.get($scope.folder.id, function (folder) {
|
||||
$q.when(folder.decrypt()).then(function (model) {
|
||||
folder.decrypt().then(function (model) {
|
||||
decFolder = model;
|
||||
folderDeferred.resolve();
|
||||
});
|
||||
@ -39,21 +39,20 @@
|
||||
promises.push(folderDeferred.promise);
|
||||
}
|
||||
|
||||
var cipherPromise = loginService.getAllDecryptedForFolder($scope.folder.id);
|
||||
cipherPromise.then(function (ciphers) {
|
||||
var cipherPromise = loginService.getAllDecryptedForFolder($scope.folder.id).then(function (ciphers) {
|
||||
if (utilsService.isEdge()) {
|
||||
// Edge is super slow at sorting
|
||||
decLogins = ciphers;
|
||||
decCiphers = ciphers;
|
||||
}
|
||||
else {
|
||||
decLogins = ciphers.sort(cipherSort);
|
||||
decCiphers = ciphers.sort(cipherSort);
|
||||
}
|
||||
});
|
||||
promises.push(cipherPromise);
|
||||
|
||||
$q.all(promises).then(function () {
|
||||
$scope.loaded = true;
|
||||
$scope.vaultLogins = decLogins;
|
||||
$scope.vaultCiphers = decCiphers;
|
||||
|
||||
if (decFolder) {
|
||||
$scope.folder.name = decFolder.name;
|
||||
@ -61,7 +60,7 @@
|
||||
|
||||
if (state.searchText) {
|
||||
$scope.searchText = state.searchText;
|
||||
$scope.searchLogins();
|
||||
$scope.searchCiphers();
|
||||
}
|
||||
|
||||
$timeout(setScrollY, 200);
|
||||
@ -106,36 +105,36 @@
|
||||
}
|
||||
|
||||
$scope.loadMore = function () {
|
||||
var pagedLength = $scope.pagedVaultLogins.length;
|
||||
if ($scope.vaultLogins.length > pagedLength) {
|
||||
$scope.pagedVaultLogins =
|
||||
$scope.pagedVaultLogins.concat($scope.vaultLogins.slice(pagedLength, pagedLength + pageSize));
|
||||
var pagedLength = $scope.pagedVaultCiphers.length;
|
||||
if ($scope.vaultCiphers.length > pagedLength) {
|
||||
$scope.pagedVaultCiphers =
|
||||
$scope.pagedVaultCiphers.concat($scope.vaultCiphers.slice(pagedLength, pagedLength + pageSize));
|
||||
}
|
||||
};
|
||||
|
||||
$scope.searchLogins = function () {
|
||||
$scope.searchCiphers = function () {
|
||||
if (!$scope.searchText || $scope.searchText.length < 2) {
|
||||
if ($scope.vaultLogins.length !== decLogins.length) {
|
||||
resetList(decLogins);
|
||||
if ($scope.vaultCiphers.length !== decCiphers.length) {
|
||||
resetList(decCiphers);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var matchedLogins = [];
|
||||
for (var i = 0; i < decLogins.length; i++) {
|
||||
if (searchCipher(decLogins[i])) {
|
||||
matchedLogins.push(decLogins[i]);
|
||||
var matchedCiphers = [];
|
||||
for (var i = 0; i < decCiphers.length; i++) {
|
||||
if (searchCipher(decCiphers[i])) {
|
||||
matchedCiphers.push(decCiphers[i]);
|
||||
}
|
||||
}
|
||||
|
||||
resetList(matchedLogins);
|
||||
resetList(matchedCiphers);
|
||||
};
|
||||
|
||||
$scope.launchWebsite = function (login) {
|
||||
$scope.launchWebsite = function (cipher) {
|
||||
$timeout(function () {
|
||||
if (login.uri.startsWith('http://') || login.uri.startsWith('https://')) {
|
||||
if (cipher.uri.startsWith('http://') || cipher.uri.startsWith('https://')) {
|
||||
$analytics.eventTrack('Launched Website From Listing');
|
||||
chrome.tabs.create({ url: login.uri });
|
||||
chrome.tabs.create({ url: cipher.uri });
|
||||
if (utilsService.inPopup($window)) {
|
||||
$window.close();
|
||||
}
|
||||
@ -143,9 +142,9 @@
|
||||
});
|
||||
};
|
||||
|
||||
function resetList(logins) {
|
||||
$scope.vaultLogins = logins;
|
||||
$scope.pagedVaultLogins = [];
|
||||
function resetList(ciphers) {
|
||||
$scope.vaultCiphers = ciphers;
|
||||
$scope.pagedVaultCiphers = [];
|
||||
$scope.loadMore();
|
||||
}
|
||||
|
||||
@ -164,7 +163,7 @@
|
||||
return false;
|
||||
}
|
||||
|
||||
$scope.addLogin = function () {
|
||||
$scope.addCipher = function () {
|
||||
storeState();
|
||||
$state.go('addLogin', {
|
||||
animation: 'in-slide-up',
|
||||
@ -173,32 +172,32 @@
|
||||
});
|
||||
};
|
||||
|
||||
$scope.viewLogin = function (login) {
|
||||
if (login.clicked) {
|
||||
login.cancelClick = true;
|
||||
$scope.launchWebsite(login);
|
||||
$scope.viewCipher = function (cipher) {
|
||||
if (cipher.clicked) {
|
||||
cipher.cancelClick = true;
|
||||
$scope.launchWebsite(cipher);
|
||||
return;
|
||||
}
|
||||
|
||||
login.clicked = true;
|
||||
cipher.clicked = true;
|
||||
|
||||
$timeout(function () {
|
||||
if (login.cancelClick) {
|
||||
login.cancelClick = false;
|
||||
login.clicked = false;
|
||||
if (cipher.cancelClick) {
|
||||
cipher.cancelClick = false;
|
||||
cipher.clicked = false;
|
||||
return;
|
||||
}
|
||||
|
||||
storeState();
|
||||
$state.go('viewLogin', {
|
||||
loginId: login.id,
|
||||
loginId: cipher.id,
|
||||
animation: 'in-slide-up',
|
||||
from: 'folder'
|
||||
});
|
||||
|
||||
// clean up
|
||||
login.cancelClick = false;
|
||||
login.clicked = false;
|
||||
cipher.cancelClick = false;
|
||||
cipher.clicked = false;
|
||||
}, 200);
|
||||
};
|
||||
|
||||
|
@ -7,12 +7,12 @@
|
||||
<i class="fa fa-search"></i>
|
||||
</div>
|
||||
<div class="right">
|
||||
<a href="" ng-click="addLogin()"><i class="fa fa-plus fa-lg"></i></a>
|
||||
<a href="" ng-click="addCipher()"><i class="fa fa-plus fa-lg"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content content-tabs">
|
||||
<!-- Folder List -->
|
||||
<div ng-if="vaultLogins.length && (showOnlyFolderView || vaultLogins.length >= 100) && vaultFolders.length && (!searchText || searchText.length < 2)">
|
||||
<div ng-if="vaultCiphers.length && (showOnlyFolderView || vaultCiphers.length >= 100) && vaultFolders.length && (!searchText || searchText.length < 2)">
|
||||
<div class="list">
|
||||
<div class="list-section" style="padding-bottom: 0;">
|
||||
<div class="list-section-header">
|
||||
@ -29,80 +29,80 @@
|
||||
</div>
|
||||
</div>
|
||||
<!-- Grouped List -->
|
||||
<div ng-if="vaultLogins.length && !showOnlyFolderView && vaultLogins.length < 100 && (!searchText || searchText.length < 2)">
|
||||
<div ng-if="vaultCiphers.length && !showOnlyFolderView && vaultCiphers.length < 100 && (!searchText || searchText.length < 2)">
|
||||
<div class="list">
|
||||
<div class="list-grouped" ng-repeat="folder in vaultFolders | orderBy: folderSort track by $index"
|
||||
ng-show="vaultFolderLogins.length">
|
||||
ng-show="vaultFolderCiphers.length">
|
||||
<div class="list-grouped-header">
|
||||
<small>{{vaultFolderLogins.length}}</small>
|
||||
<small>{{vaultFolderCiphers.length}}</small>
|
||||
<i class="fa fa-folder-open"></i> {{folder.name}}
|
||||
</div>
|
||||
<a href="#" stop-click ng-click="viewLogin(login)"
|
||||
class="list-grouped-item condensed" title="{{i18n.edit}} {{login.name}}"
|
||||
ng-repeat="login in vaultFolderLogins = (vaultLogins | filter: { folderId: folder.id }
|
||||
| filter: searchLogins() | orderBy: ['name', 'subTitle']) track by $index">
|
||||
<a href="#" stop-click ng-click="viewCipher(cipher)"
|
||||
class="list-grouped-item condensed" title="{{i18n.edit}} {{cipher.name}}"
|
||||
ng-repeat="cipher in vaultFolderCiphers = (vaultCiphers | filter: { folderId: folder.id }
|
||||
| filter: searchCiphers() | orderBy: ['name', 'subTitle']) track by $index">
|
||||
<span class="btn-list" stop-prop stop-click title="{{i18n.copyPassword}}" ngclipboard
|
||||
ngclipboard-error="clipboardError(e)" ngclipboard-success="clipboardSuccess(e, i18n.password)"
|
||||
data-clipboard-text="{{login.password}}" ng-class="{'disabled': !login.password}">
|
||||
data-clipboard-text="{{cipher.password}}" ng-class="{'disabled': !cipher.password}">
|
||||
<i class="fa fa-lg fa-key"></i>
|
||||
</span>
|
||||
<span class="btn-list" stop-prop stop-click title="{{i18n.copyUsername}}" ngclipboard
|
||||
ngclipboard-error="clipboardError(e)" ngclipboard-success="clipboardSuccess(e, i18n.username)"
|
||||
data-clipboard-text="{{login.username}}" ng-class="{'disabled': !login.username}">
|
||||
data-clipboard-text="{{cipher.username}}" ng-class="{'disabled': !cipher.username}">
|
||||
<i class="fa fa-lg fa-user"></i>
|
||||
</span>
|
||||
<span class="btn-list" stop-prop stop-click title="{{i18n.launchWebsite}}" ng-click="launchWebsite(login)"
|
||||
ng-class="{'disabled': !login.uri}">
|
||||
<span class="btn-list" stop-prop stop-click title="{{i18n.launchWebsite}}" ng-click="launchWebsite(cipher)"
|
||||
ng-class="{'disabled': !cipher.uri}">
|
||||
<i class="fa fa-lg fa-share-square-o"></i>
|
||||
</span>
|
||||
<icon uri="login.uri"></icon>
|
||||
<icon uri="cipher.uri"></icon>
|
||||
<span class="text">
|
||||
{{login.name}}
|
||||
<i class="fa fa-share-alt text-muted" ng-if="login.organizationId" title="{{i18n.shared}}"></i>
|
||||
<i class="fa fa-paperclip text-muted" ng-if="login.attachments" title="{{i18n.attachments}}"></i>
|
||||
{{cipher.name}}
|
||||
<i class="fa fa-share-alt text-muted" ng-if="cipher.organizationId" title="{{i18n.shared}}"></i>
|
||||
<i class="fa fa-paperclip text-muted" ng-if="cipher.attachments" title="{{i18n.attachments}}"></i>
|
||||
</span>
|
||||
<span class="detail">{{login.subTitle}}</span>
|
||||
<span class="detail">{{cipher.subTitle}}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Search Results List -->
|
||||
<div ng-if="vaultLogins.length && searchText && searchText.length >= 2">
|
||||
<div ng-if="vaultCiphers.length && searchText && searchText.length >= 2">
|
||||
<div class="list">
|
||||
<div class="list-section" style="padding-top: 0; padding-bottom: 0;">
|
||||
<a href="#" stop-click ng-click="viewLogin(login)"
|
||||
class="list-section-item condensed" title="{{i18n.edit}} {{login.name}}"
|
||||
ng-repeat="login in searchResults = (vaultLogins | filter: searchLogins() | orderBy: ['name', 'subTitle'])
|
||||
<a href="#" stop-click ng-click="viewCipher(cipher)"
|
||||
class="list-section-item condensed" title="{{i18n.edit}} {{cipher.name}}"
|
||||
ng-repeat="cipher in searchResults = (vaultCiphers | filter: searchCiphers() | orderBy: ['name', 'subTitle'])
|
||||
track by $index">
|
||||
<span class="btn-list" stop-prop stop-click title="{{i18n.copyPassword}}" ngclipboard
|
||||
ngclipboard-error="clipboardError(e)" ngclipboard-success="clipboardSuccess(e, i18n.password)"
|
||||
data-clipboard-text="{{login.password}}" ng-class="{'disabled': !login.password}">
|
||||
data-clipboard-text="{{cipher.password}}" ng-class="{'disabled': !cipher.password}">
|
||||
<i class="fa fa-lg fa-key"></i>
|
||||
</span>
|
||||
<span class="btn-list" stop-prop stop-click title="{{i18n.copyUsername}}" ngclipboard
|
||||
ngclipboard-error="clipboardError(e)" ngclipboard-success="clipboardSuccess(e, i18n.username)"
|
||||
data-clipboard-text="{{login.username}}" ng-class="{'disabled': !login.username}">
|
||||
data-clipboard-text="{{cipher.username}}" ng-class="{'disabled': !cipher.username}">
|
||||
<i class="fa fa-lg fa-user"></i>
|
||||
</span>
|
||||
<span class="btn-list" stop-prop stop-click title="{{i18n.launchWebsite}}" ng-click="launchWebsite(login)"
|
||||
ng-class="{'disabled': !login.uri}">
|
||||
<span class="btn-list" stop-prop stop-click title="{{i18n.launchWebsite}}" ng-click="launchWebsite(cipher)"
|
||||
ng-class="{'disabled': !cipher.uri}">
|
||||
<i class="fa fa-lg fa-share-square-o"></i>
|
||||
</span>
|
||||
<icon uri="login.uri"></icon>
|
||||
<icon uri="cipher.uri"></icon>
|
||||
<span class="text">
|
||||
{{login.name}}
|
||||
<i class="fa fa-share-alt text-muted" ng-if="login.organizationId" title="{{i18n.shared}}"></i>
|
||||
<i class="fa fa-paperclip text-muted" ng-if="login.attachments" title="{{i18n.attachments}}"></i>
|
||||
{{cipher.name}}
|
||||
<i class="fa fa-share-alt text-muted" ng-if="cipher.organizationId" title="{{i18n.shared}}"></i>
|
||||
<i class="fa fa-paperclip text-muted" ng-if="cipher.attachments" title="{{i18n.attachments}}"></i>
|
||||
</span>
|
||||
<span class="detail">{{login.subTitle}}</span>
|
||||
<span class="detail">{{cipher.subTitle}}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="centered-message" ng-if="loaded && !vaultLogins.length">
|
||||
<div class="centered-message" ng-if="loaded && !vaultCiphers.length">
|
||||
<p>
|
||||
{{i18n.noLoginsInList}}
|
||||
<button ng-click="addLogin()" style="margin-top: 20px;" class="btn btn-link btn-block">{{i18n.addLogin}}</button>
|
||||
<button ng-click="addCipher()" style="margin-top: 20px;" class="btn btn-link btn-block">{{i18n.addLogin}}</button>
|
||||
</p>
|
||||
</div>
|
||||
<div class="page-loading" ng-if="!loaded">
|
||||
|
@ -3,53 +3,53 @@
|
||||
<a ui-sref="tabs.vault({animation: 'out-slide-right'})"><i class="fa fa-chevron-left"></i> {{i18n.myVault}}</a>
|
||||
</div>
|
||||
<div class="search">
|
||||
<input type="search" placeholder="{{i18n.searchFolder}}" ng-model="searchText" ng-change="searchLogins()" id="search" />
|
||||
<input type="search" placeholder="{{i18n.searchFolder}}" ng-model="searchText" ng-change="searchCiphers()" id="search" />
|
||||
<i class="fa fa-search"></i>
|
||||
</div>
|
||||
<div class="right">
|
||||
<a href="" ng-click="addLogin()"><i class="fa fa-plus fa-lg"></i></a>
|
||||
<a href="" ng-click="addCipher()"><i class="fa fa-plus fa-lg"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="content">
|
||||
<div ng-if="vaultLogins.length" infinite-scroll="loadMore()" infinite-scroll-distance="1" infinite-scroll-parent="true"
|
||||
<div ng-if="vaultCiphers.length" infinite-scroll="loadMore()" infinite-scroll-distance="1" infinite-scroll-parent="true"
|
||||
infinite-scroll-immediate-check="true">
|
||||
<div class="list">
|
||||
<div class="list-section" style="padding-bottom: 0;">
|
||||
<div class="list-section-header">
|
||||
{{folder.name}}
|
||||
<span>{{vaultLogins.length}}</span>
|
||||
<span>{{vaultCiphers.length}}</span>
|
||||
</div>
|
||||
<a href="#" stop-click ng-click="viewLogin(login)"
|
||||
class="list-section-item condensed" title="{{i18n.edit}} {{login.name}}"
|
||||
ng-repeat="login in pagedVaultLogins track by $index">
|
||||
<a href="#" stop-click ng-click="viewCipher(cipher)"
|
||||
class="list-section-item condensed" title="{{i18n.edit}} {{cipher.name}}"
|
||||
ng-repeat="cipher in pagedVaultCiphers track by $index">
|
||||
<span class="btn-list" stop-prop stop-click title="{{i18n.copyPassword}}" ngclipboard
|
||||
ngclipboard-error="clipboardError(e)" ngclipboard-success="clipboardSuccess(e, i18n.password)"
|
||||
data-clipboard-text="{{login.password}}" ng-class="{'disabled': !login.password}">
|
||||
data-clipboard-text="{{cipher.password}}" ng-class="{'disabled': !cipher.password}">
|
||||
<i class="fa fa-lg fa-key"></i>
|
||||
</span>
|
||||
<span class="btn-list" stop-prop stop-click title="{{i18n.copyUsername}}" ngclipboard
|
||||
ngclipboard-error="clipboardError(e)" ngclipboard-success="clipboardSuccess(e, i18n.username)"
|
||||
data-clipboard-text="{{login.username}}" ng-class="{'disabled': !login.username}">
|
||||
data-clipboard-text="{{cipher.username}}" ng-class="{'disabled': !cipher.username}">
|
||||
<i class="fa fa-lg fa-user"></i>
|
||||
</span>
|
||||
<span class="btn-list" stop-prop stop-click title="{{i18n.launchWebsite}}" ng-click="launchWebsite(login)"
|
||||
ng-class="{'disabled': !login.uri}">
|
||||
<span class="btn-list" stop-prop stop-click title="{{i18n.launchWebsite}}" ng-click="launchWebsite(cipher)"
|
||||
ng-class="{'disabled': !cipher.uri}">
|
||||
<i class="fa fa-lg fa-share-square-o"></i>
|
||||
</span>
|
||||
<span class="text">
|
||||
{{login.name}}
|
||||
<i class="fa fa-share-alt text-muted" ng-if="login.organizationId" title="{{i18n.shared}}"></i>
|
||||
<i class="fa fa-paperclip text-muted" ng-if="login.attachments" title="{{i18n.attachments}}"></i>
|
||||
{{cipher.name}}
|
||||
<i class="fa fa-share-alt text-muted" ng-if="cipher.organizationId" title="{{i18n.shared}}"></i>
|
||||
<i class="fa fa-paperclip text-muted" ng-if="cipher.attachments" title="{{i18n.attachments}}"></i>
|
||||
</span>
|
||||
<span class="detail">{{login.username}}</span>
|
||||
<span class="detail">{{cipher.username}}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="centered-message" ng-if="loaded && !vaultLogins.length">
|
||||
<div class="centered-message" ng-if="loaded && !vaultCiphers.length">
|
||||
<p>
|
||||
{{i18n.noLoginsInList}}
|
||||
<button ng-click="addLogin()" style="margin-top: 20px;" class="btn btn-link btn-block">{{i18n.addLogin}}</button>
|
||||
<button ng-click="addCipher()" style="margin-top: 20px;" class="btn btn-link btn-block">{{i18n.addLogin}}</button>
|
||||
</p>
|
||||
</div>
|
||||
<div class="page-loading" ng-if="!loaded">
|
||||
|
Loading…
Reference in New Issue
Block a user