2015-02-19 21:21:54 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The application header bar.
|
|
|
|
*/
|
|
|
|
angular.module('quay').directive('headerBar', function () {
|
|
|
|
var number = 0;
|
|
|
|
var directiveDefinitionObject = {
|
|
|
|
priority: 0,
|
|
|
|
templateUrl: '/static/directives/header-bar.html',
|
|
|
|
replace: false,
|
|
|
|
transclude: false,
|
|
|
|
restrict: 'C',
|
|
|
|
scope: {
|
|
|
|
},
|
2015-05-19 21:52:44 +00:00
|
|
|
controller: function($rootScope, $scope, $element, $location, $timeout, hotkeys, UserService,
|
2015-08-03 20:56:32 +00:00
|
|
|
PlanService, ApiService, NotificationService, Config, CreateService, Features,
|
2015-09-04 20:14:46 +00:00
|
|
|
DocumentationService, ExternalLoginService) {
|
|
|
|
|
|
|
|
$scope.externalSigninUrl = ExternalLoginService.getSingleSigninUrl();
|
|
|
|
|
2015-05-19 21:52:44 +00:00
|
|
|
var hotkeysAdded = false;
|
|
|
|
var userUpdated = function(cUser) {
|
|
|
|
$scope.searchingAllowed = Features.ANONYMOUS_ACCESS || !cUser.anonymous;
|
|
|
|
|
|
|
|
if (hotkeysAdded) { return; }
|
2015-06-29 09:33:00 +00:00
|
|
|
hotkeysAdded = true;
|
2015-05-19 21:52:44 +00:00
|
|
|
|
2015-06-29 09:33:00 +00:00
|
|
|
// Register hotkeys.
|
|
|
|
if ($scope.searchingAllowed) {
|
|
|
|
hotkeys.add({
|
|
|
|
combo: '/',
|
|
|
|
description: 'Show search',
|
|
|
|
callback: function(e) {
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
$scope.toggleSearch();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
2015-04-08 19:15:21 +00:00
|
|
|
|
2015-06-29 09:33:00 +00:00
|
|
|
if (!cUser.anonymous) {
|
|
|
|
hotkeys.add({
|
|
|
|
combo: 'alt+c',
|
|
|
|
description: 'Create new repository',
|
|
|
|
callback: function(e) {
|
|
|
|
e.preventDefault();
|
|
|
|
e.stopPropagation();
|
|
|
|
$location.url('/new');
|
|
|
|
}
|
|
|
|
});
|
2015-05-19 21:52:44 +00:00
|
|
|
}
|
|
|
|
};
|
2015-04-08 18:39:52 +00:00
|
|
|
|
2015-10-22 18:56:36 +00:00
|
|
|
$scope.Config = Config;
|
2016-01-20 23:03:21 +00:00
|
|
|
$scope.Features = Features;
|
2015-02-19 21:21:54 +00:00
|
|
|
$scope.notificationService = NotificationService;
|
2015-05-19 21:52:44 +00:00
|
|
|
$scope.searchingAllowed = false;
|
2015-04-06 23:17:18 +00:00
|
|
|
$scope.searchVisible = false;
|
|
|
|
$scope.currentSearchQuery = null;
|
|
|
|
$scope.searchResultState = null;
|
2015-04-07 22:38:58 +00:00
|
|
|
$scope.showBuildDialogCounter = 0;
|
2015-02-19 21:21:54 +00:00
|
|
|
|
|
|
|
// Monitor any user changes and place the current user into the scope.
|
2015-05-19 21:52:44 +00:00
|
|
|
UserService.updateUserIn($scope, userUpdated);
|
2015-02-19 21:21:54 +00:00
|
|
|
|
2015-04-07 22:33:43 +00:00
|
|
|
$scope.currentPageContext = {};
|
|
|
|
|
|
|
|
$rootScope.$watch('currentPage.scope.viewuser', function(u) {
|
|
|
|
$scope.currentPageContext['viewuser'] = u;
|
|
|
|
});
|
|
|
|
|
|
|
|
$rootScope.$watch('currentPage.scope.organization', function(o) {
|
|
|
|
$scope.currentPageContext['organization'] = o;
|
|
|
|
});
|
|
|
|
|
|
|
|
$rootScope.$watch('currentPage.scope.repository', function(r) {
|
|
|
|
$scope.currentPageContext['repository'] = r;
|
|
|
|
});
|
2015-04-06 23:17:18 +00:00
|
|
|
|
2015-08-03 20:56:32 +00:00
|
|
|
var documentSearchMaxResults = 10;
|
|
|
|
var documentSearchScoreThreshold = 0.9;
|
|
|
|
|
|
|
|
var conductDocumentationSearch = function(query) {
|
|
|
|
if (!query) { return; }
|
|
|
|
|
|
|
|
var mapper = function(result, score) {
|
|
|
|
return {
|
|
|
|
'kind': 'doc',
|
|
|
|
'name': result.title.replace(/'\;/g, "'"),
|
|
|
|
'score': score,
|
|
|
|
'href': Config.DOCUMENTATION_LOCATION + result.url
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
DocumentationService.findDocumentation($scope, query.split(' '), function(results) {
|
|
|
|
if (!$scope.searchVisible) { return; }
|
|
|
|
|
2015-08-07 19:26:45 +00:00
|
|
|
var currentResults = $scope.searchResultState['results'] || [];
|
2015-08-03 20:56:32 +00:00
|
|
|
results.forEach(function(result) {
|
|
|
|
if (currentResults.length < documentSearchMaxResults) {
|
|
|
|
currentResults.push(result);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
$scope.searchResultState = {
|
|
|
|
'state': currentResults.length ? 'results' : 'no-results',
|
|
|
|
'results': currentResults,
|
|
|
|
'current': currentResults.length ? 0 : -1
|
|
|
|
};
|
|
|
|
}, mapper, documentSearchScoreThreshold);
|
|
|
|
}
|
|
|
|
|
2015-04-06 23:17:18 +00:00
|
|
|
var conductSearch = function(query) {
|
|
|
|
if (!query) { $scope.searchResultState = null; return; }
|
|
|
|
|
|
|
|
$scope.searchResultState = {
|
|
|
|
'state': 'loading'
|
|
|
|
};
|
|
|
|
|
|
|
|
var params = {
|
|
|
|
'query': query
|
|
|
|
};
|
|
|
|
|
|
|
|
ApiService.conductSearch(null, params).then(function(resp) {
|
2015-04-08 20:40:22 +00:00
|
|
|
if (!$scope.searchVisible || query != $scope.currentSearchQuery) { return; }
|
2015-04-06 23:17:18 +00:00
|
|
|
|
|
|
|
$scope.searchResultState = {
|
|
|
|
'state': resp.results.length ? 'results' : 'no-results',
|
|
|
|
'results': resp.results,
|
2015-04-08 19:42:19 +00:00
|
|
|
'current': resp.results.length ? 0 : -1
|
2015-04-06 23:17:18 +00:00
|
|
|
};
|
2015-08-03 20:56:32 +00:00
|
|
|
|
|
|
|
if (resp.results.length < documentSearchMaxResults) {
|
|
|
|
conductDocumentationSearch(query);
|
|
|
|
}
|
2015-04-07 22:33:43 +00:00
|
|
|
}, function(resp) {
|
|
|
|
$scope.searchResultState = null;
|
2015-04-06 23:17:18 +00:00
|
|
|
}, /* background */ true);
|
|
|
|
};
|
|
|
|
|
|
|
|
$scope.$watch('currentSearchQuery', conductSearch);
|
|
|
|
|
2015-02-19 21:21:54 +00:00
|
|
|
$scope.signout = function() {
|
|
|
|
ApiService.logout().then(function() {
|
|
|
|
UserService.load();
|
|
|
|
$location.path('/');
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
$scope.appLinkTarget = function() {
|
2015-06-25 17:03:08 +00:00
|
|
|
if ($scope._appLinkTarget) {
|
|
|
|
return $scope._appLinkTarget;
|
|
|
|
}
|
|
|
|
|
2015-02-19 21:21:54 +00:00
|
|
|
if ($("div[ng-view]").length === 0) {
|
2015-06-25 17:03:08 +00:00
|
|
|
return $scope._appLinkTarget = "_self";
|
2015-02-19 21:21:54 +00:00
|
|
|
}
|
2015-06-25 17:03:08 +00:00
|
|
|
|
|
|
|
return $scope._appLinkTarget = "";
|
2015-02-19 21:21:54 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
$scope.getEnterpriseLogo = function() {
|
|
|
|
if (!Config.ENTERPRISE_LOGO_URL) {
|
2015-10-30 17:57:53 +00:00
|
|
|
if (Features.BILLING) {
|
2016-01-20 23:03:21 +00:00
|
|
|
return '/static/img/quay-horizontal-whiteblue-nobackground.svg';
|
2015-10-30 17:57:53 +00:00
|
|
|
} else {
|
|
|
|
return '/static/img/QuayEnterprise_horizontal_color.svg'
|
|
|
|
}
|
2015-02-19 21:21:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return Config.ENTERPRISE_LOGO_URL;
|
|
|
|
};
|
2015-04-06 23:17:18 +00:00
|
|
|
|
|
|
|
$scope.toggleSearch = function() {
|
|
|
|
$scope.searchVisible = !$scope.searchVisible;
|
|
|
|
if ($scope.searchVisible) {
|
|
|
|
$('#search-box-input').focus();
|
|
|
|
if ($scope.currentSearchQuery) {
|
|
|
|
conductSearch($scope.currentSearchQuery);
|
|
|
|
}
|
|
|
|
} else {
|
2015-04-08 18:39:52 +00:00
|
|
|
$('#search-box-input').blur()
|
2015-04-06 23:17:18 +00:00
|
|
|
$scope.searchResultState = null;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
$scope.getSearchBoxClasses = function(searchVisible, searchResultState) {
|
|
|
|
var classes = searchVisible ? 'search-visible ' : '';
|
|
|
|
if (searchResultState) {
|
|
|
|
classes += 'results-visible';
|
|
|
|
}
|
|
|
|
return classes;
|
|
|
|
};
|
|
|
|
|
|
|
|
$scope.handleSearchKeyDown = function(e) {
|
2015-04-07 16:11:16 +00:00
|
|
|
if (e.keyCode == 27) {
|
|
|
|
$scope.toggleSearch();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-04-08 18:39:52 +00:00
|
|
|
var state = $scope.searchResultState;
|
|
|
|
if (!state || !state['results']) { return; }
|
2015-04-06 23:17:18 +00:00
|
|
|
|
|
|
|
if (e.keyCode == 40) {
|
2015-04-08 18:39:52 +00:00
|
|
|
state['current']++;
|
2015-04-06 23:17:18 +00:00
|
|
|
e.preventDefault();
|
|
|
|
} else if (e.keyCode == 38) {
|
2015-04-08 18:39:52 +00:00
|
|
|
state['current']--;
|
2015-04-06 23:17:18 +00:00
|
|
|
e.preventDefault();
|
|
|
|
} else if (e.keyCode == 13) {
|
2015-04-08 18:39:52 +00:00
|
|
|
var current = state['current'];
|
|
|
|
if (current >= 0 && current < state['results'].length) {
|
|
|
|
$scope.showResult(state['results'][current]);
|
2015-04-06 23:17:18 +00:00
|
|
|
}
|
|
|
|
e.preventDefault();
|
|
|
|
}
|
|
|
|
|
2015-04-08 18:39:52 +00:00
|
|
|
if (state['current'] < -1) {
|
|
|
|
state['current'] = state['results'].length - 1;
|
|
|
|
} else if (state['current'] >= state['results'].length) {
|
|
|
|
state['current'] = 0;
|
2015-04-06 23:17:18 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
$scope.showResult = function(result) {
|
|
|
|
$scope.toggleSearch();
|
|
|
|
$timeout(function() {
|
2015-08-03 20:56:32 +00:00
|
|
|
if (result['kind'] == 'doc') {
|
|
|
|
window.location = result['href'];
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-04-08 18:39:52 +00:00
|
|
|
$scope.currentSearchQuery = '';
|
2015-04-06 23:17:18 +00:00
|
|
|
$location.url(result['href'])
|
|
|
|
}, 500);
|
|
|
|
};
|
|
|
|
|
|
|
|
$scope.setCurrentResult = function(result) {
|
|
|
|
if (!$scope.searchResultState) { return; }
|
|
|
|
$scope.searchResultState['current'] = result;
|
|
|
|
};
|
2015-04-07 22:33:43 +00:00
|
|
|
|
|
|
|
$scope.getNamespace = function(context) {
|
|
|
|
if (!context) { return null; }
|
|
|
|
|
|
|
|
if (context.repository && context.repository.namespace) {
|
|
|
|
return context.repository.namespace;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (context.organization && context.organization.name) {
|
|
|
|
return context.organization.name;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (context.viewuser && context.viewuser.username) {
|
|
|
|
return context.viewuser.username;
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
};
|
|
|
|
|
|
|
|
$scope.canAdmin = function(namespace) {
|
|
|
|
if (!namespace) { return false; }
|
|
|
|
return UserService.isNamespaceAdmin(namespace);
|
|
|
|
};
|
|
|
|
|
|
|
|
$scope.isOrganization = function(namespace) {
|
|
|
|
if (!namespace) { return false; }
|
|
|
|
return UserService.isOrganization(namespace);
|
|
|
|
};
|
|
|
|
|
2015-04-07 22:38:58 +00:00
|
|
|
$scope.startBuild = function(context) {
|
|
|
|
$scope.showBuildDialogCounter++;
|
|
|
|
};
|
|
|
|
|
|
|
|
$scope.handleBuildStarted = function(build, context) {
|
|
|
|
$location.url('/repository/' + context.repository.namespace + '/' + context.repository.name + '/build/' + build.id);
|
|
|
|
};
|
|
|
|
|
2015-04-07 22:33:43 +00:00
|
|
|
$scope.createRobot = function(context) {
|
|
|
|
var namespace = $scope.getNamespace(context);
|
2015-04-23 18:40:01 +00:00
|
|
|
CreateService.askCreateRobot(namespace, function(created) {
|
|
|
|
if (UserService.isOrganization(namespace)) {
|
|
|
|
$location.url('/organization/' + namespace + '?tab=robots&showRobot=' + created.name);
|
2015-04-08 15:54:04 +00:00
|
|
|
} else {
|
2015-04-23 18:40:01 +00:00
|
|
|
$location.url('/user/' + namespace + '?tab=robots&showRobot=' + created.name);
|
2015-04-07 22:33:43 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
$scope.createTeam = function(context) {
|
|
|
|
var namespace = $scope.getNamespace(context);
|
|
|
|
if (!namespace || !UserService.isNamespaceAdmin(namespace)) { return; }
|
|
|
|
|
2015-04-23 18:40:01 +00:00
|
|
|
CreateService.askCreateTeam(namespace, function(created) {
|
|
|
|
$location.url('/organization/' + namespace + '/teams/' + created.name);
|
2015-04-07 22:33:43 +00:00
|
|
|
});
|
|
|
|
};
|
2015-02-19 21:21:54 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
return directiveDefinitionObject;
|
|
|
|
});
|