1
0
mirror of https://github.com/ansible/awx.git synced 2024-10-31 15:21:13 +03:00

Merge pull request #16 from jlmitch5/newNav

new navigation in UI
This commit is contained in:
jlmitch5 2017-09-06 17:54:21 -04:00 committed by GitHub
commit 37c2d01260
49 changed files with 677 additions and 1540 deletions

View File

@ -10,7 +10,6 @@ function LegacyCredentialsService (pathService) {
name: 'credentials', name: 'credentials',
route: '/credentials', route: '/credentials',
ncyBreadcrumb: { ncyBreadcrumb: {
parent: 'setup',
label: N_('CREDENTIALS') label: N_('CREDENTIALS')
}, },
data: { data: {

View File

@ -594,15 +594,6 @@ dd {
text-decoration: none; text-decoration: none;
} }
.navbar.site-footer {
border-top-left-radius: 0;
border-top-right-radius: 0;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
margin-bottom: 0;
background-color: @black;
}
.login-header img { .login-header img {
width: 60%; width: 60%;
} }
@ -2303,3 +2294,37 @@ input[disabled].ui-spinner-input {
.ui-dialog .ui-dialog-content { .ui-dialog .ui-dialog-content {
background: @default-bg; background: @default-bg;
} }
html { height: 100%; }
body {
font-family: 'Open Sans', sans-serif;
font-weight: 400;
color: @default-data-txt;
background-color: @default-secondary-bg;
}
.container-fluid {
padding-left: 20px;
padding-right: 20px;
}
#content-container {
padding-bottom: 0px;
}
.Panel {
background-color: @panel-bg;
border-radius: 5px;
padding: 20px;
border: 1px solid @panel-border;
margin-top: 20px;
}
.Panel-hidden {
display: none;
}
.btn {
text-transform: uppercase;
}

View File

@ -1,84 +0,0 @@
/*********************************************
* Copyright (c) 2015 Ansible, Inc.
*
* breadcrumbs.less
*
* custom breadcrumbs
*
* JT-- 7/22/14 -- changed the breadcrumbs to be all white with grey outline
*
*/
.ansible-breadcrumb {
list-style: none;
overflow: hidden;
padding: 0;
margin: 0 0 15px 0;
}
.ansible-breadcrumb li {
float: left;
height: 26px;
margin-top: 3px;
margin-bottom: 3px;
}
.ansible-breadcrumb li a {
color: @black;
font-weight: normal;
text-decoration: none;
padding: 3px 8px 3px 16px;
background: @white; /* fallback color */
position: relative;
left: 0;
top: 0;
display: block;
border-style: solid;
border-color: @grey;
border-width: thin;
float: left;
}
.ansible-breadcrumb li:first-child a{
border-top-left-radius: 4px;
border-bottom-left-radius: 4px;
padding-left: 11px;
}
.ansible-breadcrumb li.active a {
background: @white;
color: @black;
font-weight: bold;
}
.ansible-breadcrumb li a:after {
content: " ";
display: block;
width: 0;
height: 0;
border-top: 13px dashed transparent; /* Go big on the size, and let overflow hide */
border-bottom: 13px dashed transparent;
border-left: 10px solid @white;
position: absolute;
top: 50%;
margin-top: -13px;
left: 100%;
z-index: 2;
}
.ansible-breadcrumb li.active a:after {
border-left: 10px solid @white
}
.ansible-breadcrumb li a:before {
content: " ";
display: block;
width: 0;
height: 0;
border-top: 13px dashed transparent;
border-bottom: 13px dashed transparent;
border-left: 11px solid @grey;
position: absolute;
top: 50%;
margin-top: -13px;
margin-left: 1px;
left: 100%;
z-index: 1;
}
.ansible-breadcrumb li.active a:before {
border-left: 11px solid @grey;
}

View File

@ -1,183 +0,0 @@
/*********************************************
* Copyright (c) 2015 Ansible, Inc.
*
* jPushMenu.less
*
* Custom styles for slideout menu
*
*/
.cbp-spmenu {
background: #E8E8E8;
position: fixed;
}
.cbp-spmenu h3 {
color: @white;
font-size: 14px;
padding: 15px 10px 15px 10px;
margin: 0;
font-weight: 600;
background: @grey;
}
.cbp-spmenu a {
display: block;
color: @grey-txt;
font-size: 1.1em;
font-weight: 300;
}
.cbp-spmenu a:hover {
background: #D8D8D8;
color: @black;
}
.cbp-spmenu a.active {
background: #E8E8E8;
color: @black;
font-weight: 600;
}
/* Orientation-dependent styles for the content of the menu */
.cbp-spmenu-vertical {
width: 240px;
height: 100%;
top: 0;
z-index: 1100;
overflow-y:auto;
}
.cbp-spmenu-vertical a {
border-bottom: 1px solid #D8D8D8;
padding: 10px 10px 10px 20px;
}
.cbp-spmenu-horizontal {
width: 100%;
height: 150px;
left: 0;
z-index: 1000;
overflow: hidden;
}
.cbp-spmenu-horizontal h3 {
height: 100%;
width: 20%;
float: left;
}
.cbp-spmenu-horizontal a {
float: left;
width: 20%;
padding: 0.8em;
border-left: 1px solid #258ecd;
}
/* Vertical menu that slides from the left or right */
.cbp-spmenu-left {
left: -240px;
}
.cbp-spmenu-right {
right: -240px;
}
.cbp-spmenu-open.cbp-spmenu-open {
-moz-box-shadow: 3px 3px 5px 6px #ccc;
-webkit-box-shadow: 3px 3px 5px 6px #ccc;
box-shadow: 3px 3px 5px 6px #ccc;
}
.cbp-spmenu-left.cbp-spmenu-open {
left: 0px;
}
.cbp-spmenu-right.cbp-spmenu-open {
right: 0px;
}
/* Horizontal menu that slides from the top or bottom */
.cbp-spmenu-top {
top: -150px;
}
.cbp-spmenu-bottom {
bottom: -150px;
}
.cbp-spmenu-top.cbp-spmenu-open {
top: 0px;
}
.cbp-spmenu-bottom.cbp-spmenu-open {
bottom: 0px;
}
/* Push classes applied to the body */
.cbp-spmenu-push {
position: relative;
overflow-x: hidden;
left: 0;
}
.cbp-spmenu-push-toright {
left: 240px;
}
.cbp-spmenu-push-toleft {
left: -240px;
}
/* Transitions */
.cbp-spmenu,
.cbp-spmenu-push {
-webkit-transition: all 0.3s ease;
-moz-transition: all 0.3s ease;
transition: all 0.3s ease;
}
/* Example media queries */
@media screen and (max-width: 55.1875em){
.cbp-spmenu-horizontal {
font-size: 75%;
height: 110px;
}
.cbp-spmenu-top {
top: -110px;
}
.cbp-spmenu-bottom {
bottom: -110px;
}
}
@media screen and (max-height: 26.375em){
.cbp-spmenu-vertical {
font-size: 90%;
width: 190px;
}
.cbp-spmenu-left,
.cbp-spmenu-push-toleft {
left: -190px;
}
.cbp-spmenu-right {
right: -190px;
}
.cbp-spmenu-push-toright {
left: 190px;
}
}

View File

@ -1,127 +0,0 @@
/*********************************************
* Copyright (c) 2015 Ansible, Inc.
*
* main-layout.css
*
* primary page layout styles
*
*/
html { height: 100%; }
body {
font-family: 'Open Sans', sans-serif;
font-weight: 400;
color: @default-data-txt;
padding-top: 100px;
min-height: 100%;
padding-bottom: 50px;
position: relative;
background-color: @default-secondary-bg;
padding-top: 100px;
}
.container-fluid {
padding-left: 20px;
padding-right: 20px;
}
#main-menu-container {
.navbar {
margin-bottom: 0;
}
#ansible-brand-logo {
width: 160px;
height: 53px;
margin-top: 5px;
margin-left: 10px;
}
/*.navbar-collapse {
margin-left: 47px;
}*/
.collapsed-option {
display: none;
}
.nav > li > a {
padding-top: 11px;
padding-bottom: 11px;
}
}
#ansible-list-title {
display: none;
}
#content-container {
padding-bottom: 0px;
}
.group-breadcrumbs {
margin-bottom: 20px;
}
#socket-beacon-div {
display: none;
}
#socket-beacon-li {
display: block;
}
#account-submenu {
margin-right: 5px;
}
.site-footer {
height: 15px;
}
.Panel {
background-color: @panel-bg;
border-radius: 5px;
padding: 20px;
border: 1px solid @panel-border;
margin-top: 20px;
}
.Panel-hidden {
display: none;
}
.btn{
text-transform: uppercase;
}
@media (max-width: 1075px) {
#main-menu-container {
.collapsed-option {
display: block;
}
}
#ansible-list-title {
display: inline-block;
position: relative;
top: 1px;
left: 10px;
color: @default-data-txt;
text-transform:capitalize;
}
#account-menu {
display: none;
}
#account-submenu {
margin-left: 20px;
}
#socket-beacon-div {
display: block;
position: fixed;
right: 30px;
top: 5px;
margin-right: 50px;
margin-top: 15px;
}
#socket-beacon-li {
display: none;
}
}

View File

@ -1,5 +1,6 @@
@import 'action/_index'; @import 'action/_index';
@import 'input/_index'; @import 'input/_index';
@import 'layout/_index';
@import 'modal/_index'; @import 'modal/_index';
@import 'panel/_index'; @import 'panel/_index';
@import 'popover/_index'; @import 'popover/_index';

View File

@ -47,6 +47,31 @@ function ComponentsStrings (BaseString) {
DEFAULT: t.s('Copy full revision to clipboard.'), DEFAULT: t.s('Copy full revision to clipboard.'),
COPIED: t.s('Copied to clipboard.') COPIED: t.s('Copied to clipboard.')
} }
ns.layout = {
CURRENT_USER_LABEL: t.s('Logged in as'),
VIEW_DOCS: t.s('View Documentation'),
LOGOUT: t.s('Logout'),
DASHBOARD: t.s('Dashboard'),
JOBS: t.s('Jobs'),
SCHEDULES: t.s('Schedules'),
PORTAL_MODE: t.s('Portal Mode'),
PROJECTS: t.s('Projects'),
CREDENTIALS: t.s('Credentials'),
CREDENTIAL_TYPES: t.s('Credential Types'),
INVENTORIES: t.s('Inventories'),
TEMPLATES: t.s('Templates'),
ORGANIZATIONS: t.s('Organizations'),
USERS: t.s('Users'),
TEAMS: t.s('Teams'),
INVENTORY_SCRIPTS: t.s('Inventory Scripts'),
NOTIFICATIONS: t.s('Notifications'),
MANAGEMENT_JOBS: t.s('Management Jobs'),
INSTANCE_GROUPS: t.s('Instance Groups'),
SETTINGS: t.s('Settings'),
FOOTER_ABOUT: t.s('About'),
FOOTER_COPYRIGHT: t.s('Copyright © 2017 Red Hat, Inc.')
}
} }
ComponentsStrings.$inject = ['BaseStringService']; ComponentsStrings.$inject = ['BaseStringService'];

View File

@ -1,3 +1,7 @@
import layout from './layout/layout.directive';
import topNavItem from './layout/top-nav-item.directive';
import sideNav from './layout/side-nav.directive';
import sideNavItem from './layout/side-nav-item.directive';
import actionGroup from './action/action-group.directive'; import actionGroup from './action/action-group.directive';
import divider from './utility/divider.directive'; import divider from './utility/divider.directive';
import form from './form/form.directive'; import form from './form/form.directive';
@ -26,6 +30,10 @@ import ComponentsStrings from './components.strings';
angular angular
.module('at.lib.components', []) .module('at.lib.components', [])
.directive('atLayout', layout)
.directive('atTopNavItem', topNavItem)
.directive('atSideNav', sideNav)
.directive('atSideNavItem', sideNavItem)
.directive('atActionGroup', actionGroup) .directive('atActionGroup', actionGroup)
.directive('atDivider', divider) .directive('atDivider', divider)
.directive('atForm', form) .directive('atForm', form)
@ -50,5 +58,3 @@ angular
.directive('atTruncate', truncate) .directive('atTruncate', truncate)
.service('ComponentsStrings', ComponentsStrings) .service('ComponentsStrings', ComponentsStrings)
.service('BaseInputController', BaseInputController); .service('BaseInputController', BaseInputController);

View File

@ -0,0 +1,172 @@
.at-Layout {
height: 100vh;
width: 100vw;
display: flex;
&-topNav {
display: flex;
background-color: @at-color-top-nav-background;
border-bottom: @at-border-default-width solid @at-color-top-nav-border-bottom;
z-index: @at-z-index-nav;
position: fixed;
right: 0;
left: 0;
top: 0;
height: @at-height-top-nav;
.at-Layout-topNavRightAligner {
margin-left: auto;
}
.at-Layout-topNavItem {
color: @at-color-top-nav-item-text;
padding: 0 @at-padding-top-nav-item-sides;
a {
cursor: pointer;
}
a, div {
color: @at-color-top-nav-item-text;
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
i {
color: @at-color-top-nav-item-icon;
font-size: @at-height-top-nav-item-icon;
}
&--logo {
padding-left: 0px;
img {
max-width: @main-menu-max-width;
max-height: @main-menu-max-height;
height: @main-menu-height;
width: @main-menu-width;
margin: @main-menu-margin;
flex: initial;
}
}
&--user {
i {
margin-right: @at-margin-top-nav-item-between-icon-and-name;
}
}
&--socket {
i {
margin-top: @at-margin-top-nav-item-icon-socket-top-makeup;
font-size: @at-height-top-nav-item-icon-socket;
text-shadow:
-@at-border-default-width -@at-border-default-width 0 @at-color-top-nav-item-icon-socket-outline,
@at-border-default-width -@at-border-default-width 0 @at-color-top-nav-item-icon-socket-outline,
-@at-border-default-width @at-border-default-width 0 @at-color-top-nav-item-icon-socket-outline,
@at-border-default-width @at-border-default-width 0 @at-color-top-nav-item-icon-socket-outline
}
}
&:focus,
&:hover,
&.is-currentRoute {
background-color: @at-color-top-nav-item-background-hover;
}
&.is-loggedOut {
opacity: 0;
}
}
}
&-side {
background: @at-color-side-nav-background;
color: @at-color-side-nav-content;
position: fixed;
bottom: 0;
top: @at-height-top-side-nav-makeup;
overflow-y: auto;
min-height: 100vh;
min-width: @at-width-collapsed-side-nav;
.at-Layout-sideNavItem {
display: flex;
cursor: pointer;
i {
font-size: @at-height-side-nav-item-icon;
padding: @at-padding-side-nav-item-icon;
}
&:hover,
&.is-active {
background: @at-color-side-nav-item-background-hover;
border-left: @at-highlight-left-border-size solid @at-color-side-nav-item-border-hover;
i {
margin-left: @at-highlight-left-border-margin-makeup;
}
}
}
.at-Layout-sideNavSpacer {
height: @at-height-side-nav-spacer;
}
&--expanded {
width: @at-width-expanded-side-nav;
.at-Layout-sideNavItem {
display: flex;
justify-content: flex-start;
align-items: center;
padding-right: @at-padding-between-side-nav-icon-text;
text-transform: uppercase;
}
+ .at-Layout-main {
padding-left: @at-width-expanded-side-nav;
}
}
}
&-main {
display: flex;
height: 100%;
width: 100%;
flex-direction: column;
padding-left: @at-width-collapsed-side-nav;
overflow-x: hidden;
}
&-footer {
height: 40px;
background-color: @at-color-footer-background;
color: @at-color-footer;
z-index: 1040;
position: absolute;
right: @at-padding-footer-right;
left: 0;
bottom: 0;
display: flex;
align-items: center;
justify-content: flex-end;
margin-left: (@at-width-collapsed-side-nav + 5);
a {
cursor: pointer;
margin-right: @at-margin-after-footer-link;
}
}
&-side--expanded {
+ .at-Layout-main {
.at-Layout-footer {
margin-left: @at-width-expanded-side-nav;
}
}
}
}

View File

@ -0,0 +1,52 @@
function AtLayoutController ($scope, strings) {
let vm = this || {};
$scope.$on('$stateChangeSuccess', function(event, next) {
vm.currentState = next.name;
});
$scope.$watch('$root.current_user', function(val) {
vm.isLoggedIn = val && val.username;
if (val) {
vm.isSuperUser = $scope.$root.user_is_superuser || $scope.$root.user_is_system_auditor;
vm.currentUsername = val.username;
vm.currentUserId = val.id;
}
});
$scope.$watch('$root.socketStatus', function(newStatus) {
vm.socketState = newStatus;
vm.socketIconClass = "icon-socket-" + $scope.socketStatus;
});
$scope.$watch('$root.licenseMissing', function(licenseMissing) {
vm.licenseIsMissing = licenseMissing;
});
vm.getString = function(string) {
try {
return strings.get(`layout.${string}`);
} catch(err) {
return strings.get(string);
}
};
}
AtLayoutController.$inject = ['$scope', 'ComponentsStrings'];
function atLayout (pathService) {
return {
restrict: 'E',
replace: true,
transclude: true,
templateUrl: pathService.getPartialPath('components/layout/layout'),
controller: AtLayoutController,
controllerAs: 'vm',
scope: {
}
};
}
atLayout.$inject = ['PathService'];
export default atLayout;

View File

@ -0,0 +1,85 @@
<div class="at-Layout">
<div class="at-Layout-topNav">
<at-top-nav-item is-shown="missingLicense" class="at-Layout-topNavItem--logo">
<a href="/#/">
<img ng-src="/static/assets/logo-header.svg">
</a>
</at-top-nav-item>
<div class="at-Layout-topNavRightAligner"></div>
<at-top-nav-item class="at-Layout-topNavItem--user">
<a ng-href="/#/users/{{ $parent.layoutVm.currentUserId }}">
<i class="fa fa-user"
alt="{{ $parent.layoutVm.getString('CURRENT_USER_LABEL') }} {{ $parent.layoutVm.currentUsername }}">
</i>
<span>{{ $parent.layoutVm.currentUsername }}</span>
</a>
</at-top-nav-item>
<at-top-nav-item>
<a href="http://docs.ansible.com/ansible-tower/" target="_blank">
<i class="fa fa-book" alt="{{ $parent.layoutVm.getString('VIEW_DOCS') }}"></i>
</a>
</at-top-nav-item>
<at-top-nav-item class="at-Layout-topNavItem--socket"
ng-if="$parent.layoutVm.socketState &&
$parent.layoutVm.socketState !== 'ok'">
<div><i class="fa" ng-class="$parent.layoutVm.socketIconClass"></i></div>
</at-top-nav-item>
<at-top-nav-item is-shown="missingLicense">
<a href="/#/logout" is-always-shown="license">
<i class="fa fa-power-off" alt="{{ $parent.layoutVm.getString('LOGOUT') }}"></i>
</a>
</at-top-nav-item>
</div>
<at-side-nav>
<at-side-nav-item icon-class="fa-tachometer" route="dashboard" name="DASHBOARD">
</at-side-nav-item>
<at-side-nav-item icon-class="fa-spinner" route="jobs" name="JOBS">
</at-side-nav-item>
<at-side-nav-item icon-class="fa-calendar" route="jobs.schedules" name="SCHEDULES">
</at-side-nav-item>
<at-side-nav-item icon-class="fa-columns" route="portalMode.myJobs" name="PORTAL_MODE">
</at-side-nav-item>
<div class="at-Layout-sideNavSpacer"></div>
<at-side-nav-item icon-class="fa-folder-open" route="projects" name="PROJECTS">
</at-side-nav-item>
<at-side-nav-item icon-class="fa-key" route="credentials" name="CREDENTIALS">
</at-side-nav-item>
<at-side-nav-item icon-class="fa-list-alt" route="credentialTypes" name="CREDENTIAL_TYPES"
system-admin-only="true">
</at-side-nav-item>
<at-side-nav-item icon-class="fa-sitemap" route="inventories" name="INVENTORIES">
</at-side-nav-item>
<at-side-nav-item icon-class="fa-pencil-square-o" route="templates" name="TEMPLATES">
</at-side-nav-item>
<div class="at-Layout-sideNavSpacer"></div>
<at-side-nav-item icon-class="fa-building" route="organizations" name="ORGANIZATIONS">
</at-side-nav-item>
<at-side-nav-item icon-class="fa-user" route="users" name="USERS">
</at-side-nav-item>
<at-side-nav-item icon-class="fa-users" route="teams" name="TEAMS">
</at-side-nav-item>
<div class="at-Layout-sideNavSpacer"></div>
<at-side-nav-item icon-class="fa-code" route="inventoryScripts" name="INVENTORY_SCRIPTS">
</at-side-nav-item>
<at-side-nav-item icon-class="fa-bell" route="notifications" name="NOTIFICATIONS"
system-admin-only="true">
</at-side-nav-item>
<at-side-nav-item icon-class="fa-wrench" route="managementJobsList" name="MANAGEMENT_JOBS"
system-admin-only="true">
</at-side-nav-item>
<at-side-nav-item icon-class="fa-server" route="instanceGroups" name="INSTANCE_GROUPS"
system-admin-only="true">
</at-side-nav-item>
<div class="at-Layout-sideNavSpacer"></div>
<at-side-nav-item icon-class="fa-cog" route="configuration" name="SETTINGS"
system-admin-only="true">
</at-side-nav-item>
</at-side-nav>
<div class="at-Layout-main">
<ng-transclude></ng-transclude>
<div class="at-Layout-footer">
<a ui-sref="about">{{ vm.getString('FOOTER_ABOUT') }} {{ vm.getString('BRAND_NAME') }}</a>|
{{ vm.getString('FOOTER_COPYRIGHT') }}
</div>
</div>
</div>

View File

@ -0,0 +1,51 @@
function atSideNavItemLink (scope, element, attrs, ctrl) {
scope.navVm = ctrl[0];
scope.layoutVm = ctrl[1];
}
function AtSideNavItemController ($state, $scope) {
let vm = this || {};
$scope.$watch('layoutVm.currentState', function(current) {
if ($scope.name === 'portal mode') {
vm.isRoute = (current && current.indexOf('portalMode') === 0);
} else {
if (current && current.indexOf($scope.route) === 0) {
if (current.indexOf('jobs.schedules') === 0 && $scope.route === 'jobs') {
vm.isRoute = false;
} else {
vm.isRoute = true;
}
} else {
vm.isRoute = false;
}
}
});
vm.go = function() {
$state.go($scope.route, {}, {reload: true});
}
}
AtSideNavItemController.$inject = ['$state', '$scope'];
function atSideNavItem (pathService) {
return {
restrict: 'E',
templateUrl: pathService.getPartialPath('components/layout/side-nav-item'),
require: ['^^atSideNav', '^^atLayout'],
controller: AtSideNavItemController,
controllerAs: 'vm',
link: atSideNavItemLink,
scope: {
iconClass: '@',
name: '@',
route: '@',
systemAdminOnly: '@'
}
};
}
atSideNavItem.$inject = ['PathService'];
export default atSideNavItem;

View File

@ -0,0 +1,8 @@
<div class="at-Layout-sideNavItem" ng-click="vm.go()" ng-class="{'is-active': vm.isRoute}"
ng-show="(!systemAdminOnly || layoutVm.isSuperUser) && layoutVm.isLoggedIn &&
!layoutVm.licenseIsMissing">
<i class="fa {{ iconClass }}"></i>
<span class="at-Layout-sideNavItemName" ng-show="navVm.isExpanded">
{{ layoutVm.getString(name) }}
</span>
</div>

View File

@ -0,0 +1,32 @@
function atSideNavLink (scope, element, attrs, ctrl) {
scope.layoutVm = ctrl;
}
function AtSideNavController () {
let vm = this || {};
vm.isExpanded = true;
vm.toggleExpansion = () => {
vm.isExpanded = !vm.isExpanded;
}
}
function atSideNav (pathService) {
return {
restrict: 'E',
replace: true,
require: '^^atLayout',
controller: AtSideNavController,
controllerAs: 'vm',
link: atSideNavLink,
transclude: true,
templateUrl: pathService.getPartialPath('components/layout/side-nav'),
scope: {
}
};
}
atSideNav.$inject = ['PathService'];
export default atSideNav;

View File

@ -0,0 +1,8 @@
<div class="at-Layout-side"
ng-class="{'at-Layout-side--expanded': vm.isExpanded && layoutVm.isLoggedIn}">
<div class="at-Layout-sideNavItem" ng-click="vm.toggleExpansion()"
ng-show="layoutVm.isLoggedIn && !layoutVm.licenseIsMissing">
<i class="fa fa-bars"></i>
</div>
<ng-transclude></ng-transclude>
</div>

View File

@ -0,0 +1,30 @@
function atTopNavItemLink (scope, element, attrs, ctrl) {
scope.layoutVm = ctrl;
scope.isHidden = false;
var shownWhen = attrs.isShown;
if (shownWhen !== 'missingLicense') {
scope.$watch('layoutVm.licenseIsMissing', function(val) {
scope.isHidden = val;
});
}
}
function atTopNavItem (pathService) {
return {
restrict: 'E',
replace: true,
transclude: true,
templateUrl: pathService.getPartialPath('components/layout/top-nav-item'),
require: '^^atLayout',
link: atTopNavItemLink,
scope: {
}
};
}
atTopNavItem.$inject = ['PathService'];
export default atTopNavItem;

View File

@ -0,0 +1,3 @@
<div class="at-Layout-topNavItem" ng-class="{'is-loggedOut': !layoutVm.isLoggedIn}"
ng-show="!isHidden" ng-transclude>
</div>

View File

@ -20,6 +20,7 @@
// 1. Colors -------------------------------------------------------------------------------------- // 1. Colors --------------------------------------------------------------------------------------
@at-gray-light-3x: #fcfcfc; @at-gray-light-3x: #fcfcfc;
@at-gray-light-2-5x: #fafafa;
@at-gray-light-2x: #f2f2f2; @at-gray-light-2x: #f2f2f2;
@at-gray-light: #ebebeb; @at-gray-light: #ebebeb;
@at-gray: #e1e1e1; @at-gray: #e1e1e1;
@ -149,6 +150,19 @@
@at-color-table-header-background: @at-gray-light; @at-color-table-header-background: @at-gray-light;
@at-color-line-separator: @at-gray; @at-color-line-separator: @at-gray;
@at-color-top-nav-background: @at-white;
@at-color-top-nav-border-bottom: @at-gray-dark-2x;
@at-color-top-nav-item-text: @at-gray-dark-5x;
@at-color-top-nav-item-icon: @at-gray-dark-4x;
@at-color-top-nav-item-icon-socket-outline: @at-white;
@at-color-top-nav-item-background-hover: @at-gray-light-2-5x;
@at-color-side-nav-background: @at-gray-dark-4x;
@at-color-side-nav-content: @at-white;
@at-color-side-nav-item-background-hover: @at-gray-dark-2x;
@at-color-side-nav-item-border-hover: @at-white;
@at-color-footer-background: @at-gray-light-3x;
@at-color-footer: @at-gray-dark-5x;
// 2. Typography ---------------------------------------------------------------------------------- // 2. Typography ----------------------------------------------------------------------------------
@at-font-size-body: @at-font-size-3x; @at-font-size-body: @at-font-size-3x;
@ -178,6 +192,10 @@
@at-padding-popover: @at-space-2x; @at-padding-popover: @at-space-2x;
@at-padding-well: @at-space-2x; @at-padding-well: @at-space-2x;
@at-padding-input: @at-space-2x; @at-padding-input: @at-space-2x;
@at-padding-top-nav-item-sides: @at-space-4x;
@at-padding-side-nav-item-icon: @at-space-3x;
@at-padding-between-side-nav-icon-text: @at-space-3x;
@at-padding-footer-right: @at-space-4x;
@at-margin-input-message: @at-space; @at-margin-input-message: @at-space;
@at-margin-item-column: @at-space-3x; @at-margin-item-column: @at-space-3x;
@ -187,6 +205,9 @@
@at-margin-tag: @at-space-2x; @at-margin-tag: @at-space-2x;
@at-margin-form-label: @at-space; @at-margin-form-label: @at-space;
@at-margin-form-label-hint: @at-space-2x; @at-margin-form-label-hint: @at-space-2x;
@at-margin-top-nav-item-between-icon-and-name: @at-space-2x;
@at-margin-top-nav-item-icon-socket-top-makeup: -3px;
@at-margin-after-footer-link: @at-space;
@at-margin-top-search-key: @at-space-2x; @at-margin-top-search-key: @at-space-2x;
@ -195,9 +216,17 @@
@at-height-textarea: 144px; @at-height-textarea: 144px;
@at-height-button: 30px; @at-height-button: 30px;
@at-height-tab: 30px; @at-height-tab: 30px;
@at-height-top-nav: 60px;
@at-height-top-nav-item-icon: 21px;
@at-height-top-nav-item-icon-socket: 18px;
@at-height-side-nav-item-icon: 20px;
@at-height-side-nav-spacer: 20px;
@at-height-top-side-nav-makeup: 55px;
@at-width-input-button-sm: 72px; @at-width-input-button-sm: 72px;
@at-width-input-button-md: 84px; @at-width-input-button-md: 84px;
@at-width-collapsed-side-nav: 50px;
@at-width-expanded-side-nav: 200px;
// 4. Transitions --------------------------------------------------------------------------------- // 4. Transitions ---------------------------------------------------------------------------------
@ -210,3 +239,7 @@
@at-line-height-short: 0.9; @at-line-height-short: 0.9;
@at-line-height-tall: 2; @at-line-height-tall: 2;
@at-line-height: 24px; @at-line-height: 24px;
@at-highlight-left-border-size: 5px;
@at-highlight-left-border-margin-makeup: -5px;
@at-z-index-nav: 1040;
@at-border-default-width: 1px;

View File

@ -19,7 +19,6 @@
* stuff, we'd be better off managing them via npm where possible. * stuff, we'd be better off managing them via npm where possible.
*/ */
@import '../../legacy-styles/fonts'; @import '../../legacy-styles/fonts';
@import '../../legacy-styles/main-layout';
@import '../../legacy-styles/animations'; @import '../../legacy-styles/animations';
@import '../../legacy-styles/jquery-ui-overrides'; @import '../../legacy-styles/jquery-ui-overrides';
@import '../../legacy-styles/codemirror'; @import '../../legacy-styles/codemirror';
@ -29,12 +28,10 @@
@import '../../legacy-styles/job-details'; @import '../../legacy-styles/job-details';
@import '../../legacy-styles/jobs'; @import '../../legacy-styles/jobs';
@import '../../legacy-styles/inventory-edit'; @import '../../legacy-styles/inventory-edit';
@import '../../legacy-styles/breadcrumbs';
@import '../../legacy-styles/stdout'; @import '../../legacy-styles/stdout';
@import '../../legacy-styles/lists'; @import '../../legacy-styles/lists';
@import '../../legacy-styles/forms'; @import '../../legacy-styles/forms';
@import '../../legacy-styles/dashboard'; @import '../../legacy-styles/dashboard';
@import '../../legacy-styles/jPushMenu';
@import '../../legacy-styles/survey-maker'; @import '../../legacy-styles/survey-maker';
@import '../../legacy-styles/text-label'; @import '../../legacy-styles/text-label';
@import '../../legacy-styles/bootstrap-datepicker'; @import '../../legacy-styles/bootstrap-datepicker';
@ -70,7 +67,6 @@
@import '../../src/bread-crumb/bread-crumb.block.less'; @import '../../src/bread-crumb/bread-crumb.block.less';
@import '../../src/configuration/configuration.block.less'; @import '../../src/configuration/configuration.block.less';
@import '../../src/credentials/ownerList.block.less'; @import '../../src/credentials/ownerList.block.less';
@import '../../src/footer/footer.block.less';
@import '../../src/home/dashboard/counts/dashboard-counts.block.less'; @import '../../src/home/dashboard/counts/dashboard-counts.block.less';
@import '../../src/home/dashboard/graphs/dashboard-graphs.block.less'; @import '../../src/home/dashboard/graphs/dashboard-graphs.block.less';
@import '../../src/home/dashboard/lists/dashboard-list.block.less'; @import '../../src/home/dashboard/lists/dashboard-list.block.less';
@ -93,7 +89,6 @@
@import '../../src/login/loginModal/thirdPartySignOn/thirdPartySignOn.block.less'; @import '../../src/login/loginModal/thirdPartySignOn/thirdPartySignOn.block.less';
@import '../../src/login/loginModal/loginModal.block.less'; @import '../../src/login/loginModal/loginModal.block.less';
@import '../../src/login/loginModal/loginModalNotice.block.less'; @import '../../src/login/loginModal/loginModalNotice.block.less';
@import '../../src/main-menu/main-menu.block.less';
@import '../../src/management-jobs/card/mgmtcards.block.less'; @import '../../src/management-jobs/card/mgmtcards.block.less';
@import '../../src/notifications/notifications.block.less'; @import '../../src/notifications/notifications.block.less';
@import '../../src/organizations/linkout/addUsers/addUsers.block.less'; @import '../../src/organizations/linkout/addUsers/addUsers.block.less';
@ -105,10 +100,6 @@
@import '../../src/scheduler/schedulertime.block.less'; @import '../../src/scheduler/schedulertime.block.less';
@import '../../src/scheduler/scheduleToggle.block.less'; @import '../../src/scheduler/scheduleToggle.block.less';
@import '../../src/scheduler/spinnerInput.block.less'; @import '../../src/scheduler/spinnerInput.block.less';
@import '../../src/setup-menu/hover-icon.block.less';
@import '../../src/setup-menu/setup-extra.block.less';
@import '../../src/setup-menu/setup-item.block.less';
@import '../../src/setup-menu/setup-menu.block.less';
@import '../../src/shared/container/container.block.less'; @import '../../src/shared/container/container.block.less';
@import '../../src/shared/detail-nav/detail-nav.block.less'; @import '../../src/shared/detail-nav/detail-nav.block.less';
@import '../../src/shared/icon/icon.block.less'; @import '../../src/shared/icon/icon.block.less';

View File

@ -10,7 +10,7 @@ export default ['$rootScope', '$scope', '$state', 'ConfigService',
$('#about-modal').modal('show'); $('#about-modal').modal('show');
}); });
$('#about-modal').on('hidden.bs.modal', () => $state.go('setup')); $('#about-modal').on('hidden.bs.modal', () => $state.go('dashboard'));
function createSpeechBubble (brand, version) { function createSpeechBubble (brand, version) {
let text = `${brand} ${version}`; let text = `${brand} ${version}`;

View File

@ -3,7 +3,7 @@ import controller from './about.controller';
import { N_ } from '../i18n'; import { N_ } from '../i18n';
export default { export default {
name: 'setup.about', name: 'about',
route: '/about', route: '/about',
controller: controller, controller: controller,
ncyBreadcrumb: { ncyBreadcrumb: {

View File

@ -51,8 +51,6 @@ import jobSubmission from './job-submission/main';
import notifications from './notifications/main'; import notifications from './notifications/main';
import about from './about/main'; import about from './about/main';
import license from './license/main'; import license from './license/main';
import setupMenu from './setup-menu/main';
import mainMenu from './main-menu/main';
import breadCrumb from './bread-crumb/main'; import breadCrumb from './bread-crumb/main';
import browserData from './browser-data/main'; import browserData from './browser-data/main';
import configuration from './configuration/main'; import configuration from './configuration/main';
@ -67,7 +65,6 @@ import users from './users/main';
import projects from './projects/main'; import projects from './projects/main';
import RestServices from './rest/main'; import RestServices from './rest/main';
import access from './access/main'; import access from './access/main';
import footer from './footer/main';
import scheduler from './scheduler/main'; import scheduler from './scheduler/main';
import instanceGroups from './instance-groups/main'; import instanceGroups from './instance-groups/main';
@ -108,13 +105,10 @@ var awApp = angular.module('awApp', [
credentialTypes.name, credentialTypes.name,
organizations.name, organizations.name,
managementJobs.name, managementJobs.name,
setupMenu.name,
mainMenu.name,
breadCrumb.name, breadCrumb.name,
home.name, home.name,
login.name, login.name,
activityStream.name, activityStream.name,
footer.name,
workflowResults.name, workflowResults.name,
jobResults.name, jobResults.name,
jobSubmission.name, jobSubmission.name,
@ -243,18 +237,6 @@ var awApp = angular.module('awApp', [
//base.replace(/\_/g, ' '); //base.replace(/\_/g, ' ');
base = (base === 'job_events' || base === 'job_host_summaries') ? 'jobs' : base; base = (base === 'job_events' || base === 'job_host_summaries') ? 'jobs' : base;
} }
$('#ansible-list-title').html('<strong>' + base.replace(/\_/, ' ') + '</strong>');
$('#ansible-main-menu li').each(function() {
$(this).removeClass('active');
});
$('#ansible-main-menu #' + base).addClass('active');
// Apply to mobile menu as well
$('#ansible-mobile-menu a').each(function() {
$(this).removeClass('active');
});
$('#ansible-mobile-menu a[href="#' + base + '"]').addClass('active');
} }
if ($rootScope.removeConfigReady) { if ($rootScope.removeConfigReady) {

View File

@ -6,10 +6,7 @@
background-color: @bc-bg; background-color: @bc-bg;
width: 100%; width: 100%;
z-index: 1039; z-index: 1039;
position: fixed; margin-top: 60px;
right: 0;
left: 0;
top: 60px;
height: 40px; height: 40px;
border-bottom: 1px solid @bc-border; border-bottom: 1px solid @bc-border;
} }

View File

@ -26,7 +26,6 @@
}, },
ncyBreadcrumb: { ncyBreadcrumb: {
parent: 'setup',
label: N_("EDIT CONFIGURATION") label: N_("EDIT CONFIGURATION")
}, },
controller: ConfigurationController, controller: ConfigurationController,

View File

@ -41,7 +41,6 @@ angular.module('credentialTypes', [
activityStreamTarget: 'credential_type' activityStreamTarget: 'credential_type'
}, },
ncyBreadcrumb: { ncyBreadcrumb: {
parent: 'setup',
label: N_('CREDENTIAL TYPES') label: N_('CREDENTIAL TYPES')
} }
}) })

View File

@ -1,52 +0,0 @@
/** @define DashboardCounts */
.Footer {
height: 40px;
background-color: @default-secondary-bg;
color: @default-interface-txt;
width: 100%;
z-index: 1040;
position: absolute;
right: 0;
left: 0;
bottom: 0;
}
.Footer-logo {
float: left;
height: 40px;
width: 250px;
}
.Footer-logoImage {
height: 40px;
width: 250px;
}
.Footer-copyright{
float: right;
font-size: 12px;
margin-right: 20px;
margin-top: 10px;
}
.Footer-link:hover{
color: @default-bg;
}
.Footer-link{
color: @default-interface-txt;
}
.Footer-copyright.is-loggedOut,
.Footer-logo.is-loggedOut {
opacity: 0;
}
@menu-breakpoint: 553px;
@media screen and (max-width: (@menu-breakpoint)) {
.Footer-copyright{
display: none;
}
}

View File

@ -1,16 +0,0 @@
/*************************************************
* Copyright (c) 2015 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
export default
['templateUrl',
function(templateUrl) {
return {
restrict: 'E',
scope: true,
templateUrl: templateUrl('footer/footer')
};
}
];

View File

@ -1,3 +0,0 @@
<footer class='Footer'>
<div class="Footer-copyright Copyright-text" ng-class="{'is-loggedOut' : !current_user || !current_user.username}">Copyright &copy 2017 <a class="Footer-link" href="http://www.redhat.com" target="_blank">Red Hat</a>, Inc.</div>
</footer>

View File

@ -1,11 +0,0 @@
/*************************************************
* Copyright (c) 2015 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
import footerDirective from './footer.directive';
export default
angular.module('footer', [])
.directive('customFooter', footerDirective);

View File

@ -6,7 +6,6 @@ export default {
url: '/instance_groups', url: '/instance_groups',
searchPrefix: 'instance_group', searchPrefix: 'instance_group',
ncyBreadcrumb: { ncyBreadcrumb: {
parent: 'setup',
label: N_('INSTANCE GROUPS') label: N_('INSTANCE GROUPS')
}, },
params: { params: {

View File

@ -62,7 +62,6 @@ angular.module('inventoryScripts', [
activityStreamTarget: 'custom_inventory_script' activityStreamTarget: 'custom_inventory_script'
}, },
ncyBreadcrumb: { ncyBreadcrumb: {
parent: 'setup',
label: N_('INVENTORY SCRIPTS') label: N_('INVENTORY SCRIPTS')
} }
}) })

View File

@ -15,7 +15,6 @@ export default {
controller: 'licenseController', controller: 'licenseController',
data: {}, data: {},
ncyBreadcrumb: { ncyBreadcrumb: {
parent: 'setup',
label: N_('LICENSE') label: N_('LICENSE')
}, },
onEnter: ['$state', 'ConfigService', (state, configService) => { onEnter: ['$state', 'ConfigService', (state, configService) => {

View File

@ -1,306 +0,0 @@
/** @define MainMenu */
.MainMenu {
padding: 0;
display: flex;
background-color: @menu-bg;
border-bottom: 1px solid @menu-btm;
width: 100%;
z-index: 1040;
position: fixed;
right: 0;
left: 0;
top: 0;
height: 60px;
align-items: stretch;
}
.MainMenu--licenseMissing{
justify-content: space-between;
}
.MainMenu-logo,
.MainMenu-item {
color: @menu-link;
background-color: @menu-link-bg;
}
.MainMenu-logoImage {
max-width: @main-menu-max-width;
max-height: @main-menu-max-height;
height: @main-menu-height;
width: @main-menu-width;
margin: @main-menu-margin;
}
.MainMenu-logoImage--licenseMissing:hover{
cursor:default;
background-color: @default-bg!important;
}
.MainMenu-item {
padding: 0 20px;
}
.MainMenu-itemText,
.MainMenu-itemImage {
flex: initial;
}
.MainMenu-itemImage {
color: @menu-link-icon;
}
.MainMenu-socket {
background-color: @default-bg;
order: 0;
flex: initial;
padding-top: 0px;
padding-left: 20px;
padding-right: 20px;
display: flex;
align-items: center;
border: 0;
border-left: 1px solid @menu-link-sides;
cursor: default;
}
.MainMenu-socketImage {
font-size: 18px;
text-shadow:
-1px -1px 0 @default-bg,
1px -1px 0 @default-bg,
-1px 1px 0 @default-bg,
1px 1px 0 @default-bg;
z-index: 1042;
}
.MainMenu-item,
.MainMenu-item:hover,
.MainMenu-item:focus,
.MainMenu-item:active {
color: @default-interface-txt;
}
@menu-breakpoint: 900px;
@media screen and (min-width: (@menu-breakpoint + 1px)) {
.MainMenu-mobileItems,
.MainMenu-toggle {
display: none;
}
.MainMenu-logo {
flex: initial;
padding: 0;
display: flex;
align-items: center;
border: 0;
border-bottom: 0;
border-right: 1px solid @menu-link-sides;
}
.MainMenu-item {
flex: initial;
padding-top: 0px;
border: 0;
border-bottom: 0px solid @menu-link-btm-hov;
display: flex;
align-items: center;
}
// Set up elements based on if their layout in the menu bar
.MainMenu-item--left {
border-right: 1px solid @menu-link-sides;
}
.MainMenu-item--left:hover,
.MainMenu-item--left.is-currentRoute {
margin-left: -1px;
padding-left: 21px;
padding-right: 21px;
border-right: 0px;
}
.MainMenu-item--lastLeft {
margin-right: auto;
}
.MainMenu-item--right {
border-left: 1px solid @menu-link-sides;
order: 1;
}
.MainMenu-item--right:hover,
.MainMenu-item--right.is-currentRoute {
border-left: 0px;
padding-left: 21px;
padding-right: 21px;
margin-right: -1px;
}
.MainMenu-item:hover,
.MainMenu-item.is-currentRoute {
padding-top: 5px;
border-bottom: 5px solid @menu-link-btm-hov;
}
.MainMenu-itemText--username {
padding-left: 13px;
margin-top: -4px;
max-width: 85px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.MainMenu-itemImage {
font-size: 20px;
}
.MainMenu-itemImage--settings {
margin-top: -1px;
}
.MainMenu-itemImage--user {
font-size: 21px;
margin-right: -5px;
margin-top: -1px;
}
.MainMenu-itemImage--docs {
font-size: 21px;
margin-top: -2px;
}
.MainMenu-item.is-currentRoute {
background-color: @menu-link-bg-hov;
}
}
@media screen and (max-width: @menu-breakpoint) {
.MainMenu-logo {
height: 60px;
}
.MainMenu-logoImage {
margin-top: @main-menu-margin-top-breakpoint;
}
.MainMenu-item--notMobile {
display: none;
}
.MainMenu-item--licenseMissing{
justify-content: space-between!important;
display:flex!important;
align-items: center!important;
flex: initial!important;
padding-top:0px;
}
.MainMenu-item--licenseMissing:hover{
padding-top:20px;
border-bottom: 5px solid @menu-link-btm-hov;
}
.MainMenu-itemImage--licenseMissing{
font-size: 20px!important;
}
.MainMenu {
flex-direction: row;
flex-wrap: wrap;
}
.MainMenu-logo {
flex: 1;
border-bottom: 1px solid @menu-link-btm;
order: 0;
}
.MainMenu-mobileItems {
display: flex;
order: 2;
flex-direction: row;
flex-wrap: wrap;
font-size: 15px;
width: 100%;
visibility: visible;
opacity: 1;
height: 416px;
}
.MainMenu-mobileItems.is-hiddenOnMobile,
.MainMenu-mobileItems.is-loggedOut {
visibility: hidden;
opacity: 0;
height: 0;
}
.MainMenu-item {
flex: 0 0 100%;
padding-top: 15px;
padding-bottom: 15px;
order: 1;
border-bottom: 1px solid @menu-link-btm;
}
.MainMenu-item.is-currentRoute {
font-weight: bold;
background-color: @menu-link-bg;
}
.MainMenu-item:hover {
background-color: @menu-link-bg-hov;
}
.MainMenu-toggle {
color: @menu-link-icon;
background-color: @menu-link-bg;
order: 0;
flex: initial;
padding-top: 3px;
padding-left: 15px;
padding-right: 15px;
font-size: 34px;
display: flex;
align-items: center;
border: 0;
border-left: 1px solid @menu-link-btm;
border-bottom: 1px solid @menu-link-btm;
}
.MainMenu-socket {
border-bottom: 1px solid @menu-link-btm;
}
.MainMenu-toggleImage {
width: 36px;
}
}
.MainMenu-toggle:focus,
.MainMenu-item:focus,
.MainMenu-logo:focus,
.MainMenu-toggle:hover,
.MainMenu-item:hover,
.MainMenu-logo:hover,
.MainMenu-item.is-currentRoute {
background-color: @default-tertiary-bg;
}
// item on
.MainMenu-logo,
.MainMenu-item,
.MainMenu-socket,
.MainMenu-toggle {
opacity: 1;
}
.MainMenu-logo.is-loggedOut,
.MainMenu-item.is-loggedOut,
.MainMenu-socket.is-loggedOut,
.MainMenu-toggle.is-loggedOut {
opacity: 0;
}

View File

@ -1,56 +0,0 @@
/* jshint unused: vars */
export default
[ '$state', 'templateUrl', '$rootScope', function($state, templateUrl, $rootScope) {
return {
restrict: 'E',
templateUrl: templateUrl('main-menu/main-menu'),
link: function(scope, element, attrs) {
scope.isCurrentState = function(name){
return $state.current.name === name;
};
scope.includesCurrentState = function(name){
return $state.includes(name);
};
// set up the user tooltip
$rootScope.$on('current_user', function(user) {
scope.currentUserTip = "Logged in as " + user.un;
});
// set up things for the socket notification
scope.socketHelp = $rootScope.socketHelp;
scope.socketTip = $rootScope.socketTip;
$rootScope.$watch('socketStatus', function(newStatus) {
scope.socketStatus = newStatus;
scope.socketIconClass = "icon-socket-" + scope.socketStatus;
});
$rootScope.$watch('socketTip', function(newTip) {
scope.socketTip = newTip;
});
// default the mobile menu as hidden
scope.isHiddenOnMobile = true;
// set up the click function to toggle mobile menu
scope.toggleMenu = function() {
if (scope.isHiddenOnMobile) {
scope.isHiddenOnMobile = false;
} else {
scope.isHiddenOnMobile = true;
}
};
// if the user clicks outside of the mobile menu,
// close it if it's open
$("body").on('click', function(e) {
if ($(e.target).parents(".MainMenu").length === 0) {
scope.isHiddenOnMobile = true;
}
});
// close the menu when the user clicks a link to a different route
scope.$on('$locationChangeStart', function(event) {
scope.isHiddenOnMobile = true;
});
}
};
}];

View File

@ -1,225 +0,0 @@
<nav id="main_menu" class="MainMenu" ng-class="{'MainMenu--licenseMissing' : licenseMissing}">
<!-- Menu logo item -->
<a id="main_menu_logo"
href="/#/"
class="MainMenu-logo ng-cloak"
ng-class="{'is-loggedOut' : !current_user || !current_user.username, 'MainMenu-logoImage--licenseMissing': licenseMissing}">
<img class="MainMenu-logoImage"
ng-class="{'MainMenu-logoImage--licenseMissing': licenseMissing}"
ng-src="/static/assets/logo-header.svg">
</a>
<!-- Mobile menu items -->
<span id="main_menu_mobile_items" class="MainMenu-mobileItems" ng-class="{'is-hiddenOnMobile': isHiddenOnMobile, 'is-loggedOut' : !current_user || !current_user.username}">
<a class="MainMenu-item"
id="main_menu_projects_mobile_link"
href="/#/projects"
ng-class="{'is-currentRoute' : isCurrentState('projects')}">
<span class="MainMenu-itemText">
<translate>PROJECTS</translate>
</span>
</a>
<a class="MainMenu-item"
id="main_menu_inventories_mobile_link"
href="/#/inventories"
ng-class="{'is-currentRoute' : isCurrentState('inventories')}">
<span class="MainMenu-itemText">
<translate>INVENTORIES</translate>
</span>
</a>
<a class="MainMenu-item"
id="main_menu_job_templates_mobile_link"
href="/#/templates"
ng-class="{'is-currentRoute' : isCurrentState('templates')}">
<span class="MainMenu-itemText">
<translate>TEMPLATES</translate>
</span>
</a>
<a class="MainMenu-item"
id="main_menu_jobs_mobile_link"
href="/#/jobs"
ng-class="{'is-currentRoute' : isCurrentState('jobs')}">
<span class="MainMenu-itemText">
<translate>JOBS</translate>
</span>
</a>
<a class="MainMenu-item"
id="main_menu_current_user_mobile_link"
ng-href="/#/users/{{ $root.current_user.id }}"
ng-class="{'is-currentRoute' : isCurrentState('users.edit')}">
<span class="MainMenu-itemText">
<translate>VIEW USER PAGE FOR {{ $root.current_user.username | uppercase }}</translate>
</span>
</a>
<a class="MainMenu-item"
id="main_menu_setup_mobile_link"
ng-href="/#/setup"
ng-class="{'is-currentRoute' : isCurrentState('setup')}">
<span class="MainMenu-itemText">
<translate>SETTINGS</translate>
</span>
</a>
<a class="MainMenu-item"
id="main_menu_setup_mobile_link"
ui-sref="portalMode"
ng-class="{'is-currentRoute' : isCurrentState('portalMode')}">
<span class="MainMenu-itemText">
<translate>PORTAL MODE</translate>
</span>
</a>
<a class="MainMenu-item"
id="main_menu_docs_mobile_link"
ng-href="http://docs.ansible.com/ansible-tower/"
target="_blank">
<span class="MainMenu-itemText">
<translate>VIEW DOCUMENTATION</translate>
</span>
</a>
<a class="MainMenu-item"
id="main_menu_logout_mobile_link"
ng-href="/#/logout"
ng-class="{'is-currentRoute' : isCurrentState('logout')}">
<span class="MainMenu-itemText">
<translate>LOG OUT</translate>
</span>
</a>
</span>
<!-- Non-mobile menu items -->
<a class="MainMenu-item MainMenu-item--notMobile MainMenu-item--left ng-cloak"
id="main_menu_projects_link"
href="/#/projects"
ng-hide="licenseMissing"
ng-class="{'is-currentRoute' : isCurrentState('projects'), 'is-loggedOut' : !current_user || !current_user.username}">
<span class="MainMenu-itemText">
<translate>PROJECTS</translate>
</span>
</a>
<a class="MainMenu-item MainMenu-item--notMobile MainMenu-item--left"
id="main_menu_inventories_link"
href="/#/inventories"
ng-hide="licenseMissing"
ng-class="{'is-currentRoute' : isCurrentState('inventories'), 'is-loggedOut' : !current_user || !current_user.username}">
<span class="MainMenu-itemText">
<translate>INVENTORIES</translate>
</span>
</a>
<a class="MainMenu-item MainMenu-item--notMobile MainMenu-item--left"
id="main_menu_job_templates_link"
href="/#/templates"
ng-hide="licenseMissing"
ng-class="{'is-currentRoute' : isCurrentState('templates'), 'is-loggedOut' : !current_user || !current_user.username}">
<span class="MainMenu-itemText">
<translate>TEMPLATES</translate>
</span>
</a>
<a class="MainMenu-item MainMenu-item--notMobile MainMenu-item--left MainMenu-item--lastLeft"
id="main_menu_jobs_link"
href="/#/jobs"
ng-hide="licenseMissing"
ng-class="{'is-currentRoute' : isCurrentState('jobs'), 'is-loggedOut' : !current_user || !current_user.username}">
<span class="MainMenu-itemText">
<translate>JOBS</translate>
</span>
</a>
<a class="MainMenu-item MainMenu-item--notMobile MainMenu-item--user MainMenu-item--right"
id="main_menu_current_user_link"
ng-href="/#/users/{{ $root.current_user.id }}"
ng-hide="licenseMissing"
ng-class="{'is-currentRoute' : isCurrentState('users.edit'), 'is-loggedOut' : !current_user || !current_user.username}"
aw-tool-tip="{{currentUserTip}}"
aw-tip-watch="currentUserTip"
data-placement="bottom"
data-trigger="hover"
data-container="body">
<i class="MainMenu-itemImage MainMenu-itemImage--user icon-user"
alt="Logged in as {{ $root.current_user.username}}">
</i>
<span class="MainMenu-itemText MainMenu-itemText--username">
{{ $root.current_user.username}}
</span>
</a>
<a class="MainMenu-item MainMenu-item--notMobile MainMenu-item--right"
id="main_menu_setup_link"
ng-href="/#/setup"
ng-hide="licenseMissing"
ng-class="{'is-currentRoute' : isCurrentState('setup'), 'is-loggedOut' : !current_user || !current_user.username}"
aw-tool-tip="{{'Settings'|translate}}"
data-placement="bottom"
data-trigger="hover"
data-container="body">
<i class="MainMenu-itemImage MainMenu-itemImage--settings fa fa-cog"
alt="Settings">
</i>
</a>
<a class="MainMenu-item MainMenu-item--notMobile MainMenu-item--right"
id="main_menu_portal_link"
ng-href="/#/portal/myjobs"
ng-hide="licenseMissing"
ng-class="{'is-currentRoute' : isCurrentState('portalMode'), 'is-loggedOut' : !current_user || !current_user.username}"
aw-tool-tip="{{'My View'|translate}}"
data-placement="bottom"
data-trigger="hover"
data-container="body">
<i class="MainMenu-itemImage MainMenu-itemImage--settings fa fa-tasks"
alt="Portal Mode">
</i>
</a>
<a class="MainMenu-item MainMenu-item--notMobile MainMenu-item--right"
id="main_menu_docs_link"
ng-href="http://docs.ansible.com/ansible-tower/"
ng-hide="licenseMissing"
ng-class="{'is-loggedOut' : !current_user || !current_user.username}"
aw-tool-tip="{{'View Documentation'|translate}}"
data-placement="bottom"
data-trigger="hover"
data-container="body"
target="_blank">
<i class="MainMenu-itemImage MainMenu-itemImage--docs fa fa-book"
alt="View Documentation">
</i>
</a>
<a class="MainMenu-item MainMenu-item--notMobile MainMenu-item--right"
id="main_menu_logout_link"
ng-href="/#/logout"
ng-class="{'is-currentRoute' : isCurrentState('logout'),
'is-loggedOut' : !current_user || !current_user.username,
'MainMenu-item--licenseMissing' : licenseMissing}"
aw-tool-tip="{{'Log Out'|translate}}"
data-placement="bottom"
data-trigger="hover"
data-container="body"
data-tooltip_inner_class="tooltip-inner--logOut">
<i class="MainMenu-itemImage fa fa-power-off"
ng-class="{'MainMenu-itemImage--licenseMissing' : licenseMissing}"
alt="Log Out">
</i>
</a>
<!-- Socket-status item -->
<div
id="main_menu_socket_status_notification"
class="MainMenu-socket"
aw-tool-tip="{{socketTip}}"
tip-watch="socketTip"
data-placement="bottom"
data-trigger="hover"
data-container="body"
ng-class="{'is-loggedOut' : !current_user || !current_user.username}"
ng-hide="licenseMissing"
ng-if="socketStatus && socketStatus !== 'ok'">
<i class="fa MainMenu-socketImage"
ng-class="socketIconClass">
</i>
</div>
<!-- Mobile menu toggle item -->
<button
id="main_menu_mobile_toggle_button"
class="MainMenu-toggle"
ng-hide="licenseMissing"
ng-class="{'is-active': !isHiddenOnMobile, 'is-loggedOut' : !current_user || !current_user.username}"
ng-click="toggleMenu()">
<i class="fa fa-bars MainMenu-toggleImage"></i>
</button>
</nav>

View File

@ -1,5 +0,0 @@
import mainMenu from './main-menu.directive';
export default
angular.module('mainMenu', [])
.directive('mainMenu', mainMenu);

View File

@ -17,7 +17,6 @@ export default {
activityStreamTarget: 'job' activityStreamTarget: 'job'
}, },
ncyBreadcrumb: { ncyBreadcrumb: {
parent: 'setup',
label: N_('MANAGEMENT JOBS') label: N_('MANAGEMENT JOBS')
}, },
}; };

View File

@ -39,7 +39,6 @@ angular.module('notifications', [
name: 'notifications', name: 'notifications',
url: '/notification_templates', url: '/notification_templates',
ncyBreadcrumb: { ncyBreadcrumb: {
parent: 'setup',
label: N_("NOTIFICATIONS") label: N_("NOTIFICATIONS")
}, },
lazyLoad: () => stateDefinitions.generateTree({ lazyLoad: () => stateDefinitions.generateTree({
@ -87,7 +86,6 @@ angular.module('notifications', [
activityStreamTarget: 'notification_template' activityStreamTarget: 'notification_template'
}, },
ncyBreadcrumb: { ncyBreadcrumb: {
parent: 'setup',
label: N_('NOTIFICATIONS') label: N_('NOTIFICATIONS')
} }
}) })

View File

@ -48,7 +48,6 @@ angular.module('Organizations', [
list: templateUrl('organizations/list/organizations-list') list: templateUrl('organizations/list/organizations-list')
}, },
ncyBreadcrumb: { ncyBreadcrumb: {
parent: 'setup',
label: N_('ORGANIZATIONS') label: N_('ORGANIZATIONS')
}, },
data: { data: {

View File

@ -1,45 +0,0 @@
/** @define HoverIcon */
.HoverIcon {
@media screen and (max-width: 571px) {
&--onlyLarge {
.HoverIcon-icon--opacity {
opacity: 1;
}
.HoverIcon-icon--height {
height: 22px;
}
}
}
&-icon {
width: auto;
&--color {
g, path {
transition: fill 0.15s ease-out;
}
}
&--opacity {
transition: opacity 0.3s ease-out;
opacity: 0;
}
&--height {
transition: height 0.2s ease-out;
height: 0;
}
}
&:hover {
.HoverIcon-icon {
&--opacity {
opacity: 1;
}
&--height {
height: 22px;
}
&--color {
path, g {
fill: @blue;
}
}
}
}
}

View File

@ -1,12 +0,0 @@
import route from './setup.route';
import icon from '../shared/icon/main';
export default
angular.module('setupMenu',
[ icon.name])
.run(['$stateExtender', 'I18NInit',
function($stateExtender, I18NInit) {
I18NInit();
$stateExtender.addState(route);
}]);

View File

@ -1,14 +0,0 @@
/** @define SetupExtra */
.SetupExtra {
&-itemTitle {
font-size: 1.4rem;
font-weight: bold;
}
&-itemDescription {
font-family: merriweather;
font-size: 1rem;
font-weight: lighter;
font-style: italic;
}
}

View File

@ -1,73 +0,0 @@
/** @define SetupItem */
.SetupItem {
background-color: @panel-bg;
border-radius: 5px;
border: 1px solid @b7grey;
min-height: 120px;
padding: 20px;
margin-top: 20px;
transition: background-color 0.2s;
cursor:pointer;
}
.SetupItem:hover {
background-color: @btn-bg-hov;
}
.SetupItem-title{
font-size: 14px;
color: @default-interface-txt;
text-align: center;
margin-bottom: 15px;
font-weight: 600;
text-transform: uppercase;
margin-top: 0;
}
.SetupItem-description{
font-size: 12px;
color: @default-interface-txt;
text-align: center;
margin-bottom: 0;
}
@media (min-width: 1179px) {
.SetupItem {
width: ~"calc(25% - 20px)";
margin-right: 20px;
}
.SetupItem :nth-child(4n+4) {
margin-right: 0px;
}
}
@media (min-width: 901px) and (max-width: 1178px) {
.SetupItem {
width: ~"calc(33% - 11px)";
margin-right: 20px;
}
.SetupItem:nth-child(3n+3) {
margin-right: 0px;
}
}
@media (min-width: 616px) and (max-width: 900px) {
.SetupItem {
width: ~"calc(50% - 10px)";
margin-right: 20px;
}
.SetupItem:nth-child(2n+2) {
margin-right: 0px;
}
}
@media (max-width: 615px) {
.SetupItem {
width: 100%;
margin-right: 0px;
}
}

View File

@ -1,13 +0,0 @@
/** @define SetupMenu */
@menu-breakpoint: 710px;
.SetupMenu {
width: 100%;
margin-left: 0;
display: flex;
flex-wrap: wrap;
@media screen and (max-width: @menu-breakpoint) {
margin-left: 0px;
}
}

View File

@ -1,79 +0,0 @@
<section id="htmlTemplate" class="Container">
<div class="SetupMenu">
<a ui-sref="organizations" class="SetupItem">
<h4 class="SetupItem-title " translate>Organizations</h4>
<p class="SetupItem-description" translate>
Group all of your content to manage permissions across departments in your company.
</p>
</a>
<a ui-sref="users" class="SetupItem">
<h4 class="SetupItem-title" translate>Users</h4>
<p class="SetupItem-description" translate>
Allow others to sign into {{BRAND_NAME}} and own the content they create.
</p>
</a>
<a ui-sref="teams" class="SetupItem">
<h4 class="SetupItem-title" translate>Teams</h4>
<p class="SetupItem-description" translate>
Split up your organization to associate content and control permissions for groups.
</p>
</a>
<a ui-sref="credentials" class="SetupItem">
<h4 class="SetupItem-title" translate>Credentials</h4>
<p class="SetupItem-description" translate>
Add passwords, SSH keys, and other credentials to use when launching jobs against machines, or when syncing inventories or projects.
</p>
</a>
<a ui-sref="credentialTypes" class="SetupItem"
ng-if="user_is_system_auditor || user_is_superuser">
<h4 class="SetupItem-title" translate>Credential Types</h4>
<p class="SetupItem-description" translate>
Create custom credential types to be used for authenticating to network hosts and cloud sources
</p>
</a>
<a ui-sref="managementJobsList" class="SetupItem" ng-if="user_is_superuser || user_is_system_auditor">
<h4 class="SetupItem-title" translate>Management Jobs</h4>
<p class="SetupItem-description" translate>
Manage the cleanup of old job history, activity streams, data marked for deletion, and system tracking info.
</p>
</a>
<a ui-sref="inventoryScripts" class="SetupItem">
<h4 class="SetupItem-title" translate>Inventory Scripts</h4>
<p class="SetupItem-description" translate>
Create and edit scripts to dynamically load hosts from any source.
</p>
</a>
<a ui-sref="notifications" class="SetupItem"
ng-if="orgAdmin || user_is_system_auditor || user_is_superuser">
<h4 class="SetupItem-title" translate>Notifications</h4>
<p class="SetupItem-description" translate>
Create templates for sending notifications with Email, HipChat, Slack, and SMS.
</p>
</a>
<a ui-sref="instanceGroups" class="SetupItem">
<h4 class="SetupItem-title" translate>Instance Groups</h4>
<p class="SetupItem-description" translate>
View list and capacity of {{BRAND_NAME}} instances.
</p>
</a>
<a ui-sref="configuration" class="SetupItem" ng-if="user_is_superuser || user_is_system_auditor">
<h4 class="SetupItem-title" translate>Configure {{BRAND_NAME}}</h4>
<p class="SetupItem-description" translate>
Edit {{BRAND_NAME}}'s configuration.
</p>
</a>
<a ui-sref="setup.about" class="SetupItem">
<h4 class="SetupItem-title" translate>About {{BRAND_NAME}}</h4>
<p class="SetupItem-description" translate>
View information about this version of Ansible {{BRAND_NAME}}.
</p>
</a>
<a ui-sref="license" class="SetupItem" ng-if="!isOpen">
<h4 class="SetupItem-title" translate>View Your License</h4>
<p class="SetupItem-description" translate>
View and edit your license information.
</p>
</a>
</div>
<div ui-view></div>
</section>

View File

@ -1,48 +0,0 @@
import {templateUrl} from '../shared/template-url/template-url.factory';
import { N_ } from '../i18n';
import _ from 'lodash';
export default {
name: 'setup',
route: '/setup',
ncyBreadcrumb: {
label: N_("SETTINGS")
},
templateUrl: templateUrl('setup-menu/setup-menu'),
controller: function(config, orgAdmin, $scope){
$scope.isOpen = _.get(config, 'license_info.license_type') === 'open';
$scope.orgAdmin = orgAdmin;
},
resolve: {
config: ['ConfigService', config => config.getConfig()],
orgAdmin:
['$rootScope', 'ProcessErrors', 'Rest', 'GetBasePath',
function($rootScope, ProcessErrors, Rest, GetBasePath){
return $rootScope.loginConfig.promise.then(function () {
if($rootScope.current_user.related.admin_of_organizations){
$rootScope.orgAdmin = false;
if ($rootScope.current_user.is_superuser) {
return true;
} else {
Rest.setUrl(GetBasePath('users') + `${$rootScope.current_user.id}/admin_of_organizations`);
return Rest.get().then(function(data){
if(data.data.count){
return true;
}
else{
return false;
}
})
.catch(function (data, status) {
ProcessErrors($rootScope, data, status, null, { hdr: 'Error!', msg: 'Failed to find if users is admin of org' + status });
});
}
}
else{
return false;
}
});
}]
}
};

View File

@ -42,7 +42,6 @@ angular.module('Teams', [])
activityStreamTarget: 'team' activityStreamTarget: 'team'
}, },
ncyBreadcrumb: { ncyBreadcrumb: {
parent: 'setup',
label: N_('TEAMS') label: N_('TEAMS')
} }
}) })

View File

@ -42,7 +42,6 @@ angular.module('Users', [])
activityStreamTarget: 'user' activityStreamTarget: 'user'
}, },
ncyBreadcrumb: { ncyBreadcrumb: {
parent: 'setup',
label: N_('USERS') label: N_('USERS')
} }
}) })

View File

@ -18,7 +18,7 @@
</head> </head>
<body data-user-agent="{{userAgent}}"> <body data-user-agent="{{userAgent}}">
<main-menu></main-menu> <at-layout>
<bread-crumb></bread-crumb> <bread-crumb></bread-crumb>
<toast></toast> <toast></toast>
<div class="container-fluid" id="content-container"> <div class="container-fluid" id="content-container">
@ -157,7 +157,7 @@
<p>{% trans 'working...' %}</p> <p>{% trans 'working...' %}</p>
</div> </div>
</div> </div>
<custom-footer></custom-footer> </at-layout>
</body> </body>
</html> </html>