Merge branch 'devel' into workflow-visualizer-search

This commit is contained in:
Daniel Sami 2018-10-18 14:48:36 -04:00 committed by GitHub
commit f3ee93b67f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
63 changed files with 776 additions and 818 deletions

View File

@ -13,3 +13,4 @@
@import 'truncate/_index';
@import 'utility/_index';
@import 'code-mirror/_index';
@import 'cards/_index';

View File

@ -0,0 +1,51 @@
/* Cards Group */
.at-CardContainer {
padding: 20px;
}
.at-CardGroup {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
grid-gap: 20px;
}
/* Card */
.at-Card {
min-height: 103px;
display: flex;
flex-direction: column;
flex: 1;
background-color: @at-white;
text-decoration: none;
text-align: center;
padding: 20px;
border-left: 3px solid @at-white;
border-radius: 2px;
box-shadow: 0px 3px 1px -2px rgba(0, 0, 0, 0.2), 0px 2px 2px 0px rgba(0, 0, 0, 0.14), 0px 1px 5px 0px rgba(0, 0, 0, 0.12);
transition: box-shadow 280ms cubic-bezier(0.4, 0, 0.2, 1);
cursor: pointer;
}
.at-Card:hover {
background-color: @at-color-body-background;
border-left: 3px solid @at-blue;
box-shadow: 0px 2px 4px -1px rgba(0, 0, 0, 0.2), 0px 4px 5px 0px rgba(0, 0, 0, 0.14), 0px 1px 10px 0px rgba(0, 0, 0, 0.12);
}
.at-Card-title {
font-size: 14px;
color: @at-gray-70;
font-weight: bold;
line-height: 14px;
}
.at-Card-text {
font-size: 12px;
color: @at-gray-161b1f;
}
/* Spacers */
.at-Card--spacer {
min-height: 15px;
}

View File

@ -0,0 +1,14 @@
const templateUrl = require('~components/cards/card.partial.html');
function atCard () {
return {
restrict: 'E',
transclude: true,
templateUrl,
scope: {
title: '@',
},
};
}
export default atCard;

View File

@ -0,0 +1,5 @@
<a class="at-Card" >
<span class="at-Card-title" translate>{{ title }}</span>
<span class="at-Card--spacer"></span>
<span class="at-Card-text" ng-transclude></span>
</a>

View File

@ -0,0 +1,11 @@
const templateUrl = require('~components/cards/group.partial.html');
function atCardGroup () {
return {
restrict: 'E',
transclude: true,
templateUrl,
};
}
export default atCardGroup;

View File

@ -0,0 +1,4 @@
<div class="at-CardContainer">
<div class="at-CardGroup" ng-transclude>
</div>
</div>

View File

@ -37,6 +37,8 @@ import toggleTag from '~components/toggle-tag/toggle-tag.directive';
import topNavItem from '~components/layout/top-nav-item.directive';
import truncate from '~components/truncate/truncate.directive';
import atCodeMirror from '~components/code-mirror';
import card from '~components/cards/card.directive';
import cardGroup from '~components/cards/group.directive';
import BaseInputController from '~components/input/base.controller';
import ComponentsStrings from '~components/components.strings';
@ -84,6 +86,8 @@ angular
.directive('atToggleTag', toggleTag)
.directive('atTopNavItem', topNavItem)
.directive('atTruncate', truncate)
.directive('atCard', card)
.directive('atCardGroup', cardGroup)
.service('BaseInputController', BaseInputController)
.service('ComponentsStrings', ComponentsStrings);

View File

@ -1,5 +1,5 @@
.at-Layout {
height: 100vh;
min-height: 100vh;
width: 100vw;
display: flex;
@ -82,17 +82,13 @@
}
}
&-side {
&-sideContainer {
background: @at-color-side-nav-background;
position: fixed;
bottom: 0;
top: @at-height-top-side-nav-makeup;
overflow-y: auto;
max-height: 100vh;
min-width: @at-width-collapsed-side-nav;
}
&-side {
margin-top: @at-height-top-side-nav-makeup;
width: @at-width-collapsed-side-nav;
overflow-x: hidden;
z-index: @at-z-index-side-nav;
.at-Popover-container {
margin-top: 2px;
@ -120,6 +116,10 @@
width: 50px;
}
i.is-no-tooltip {
padding-left: @at-padding-left-side-nav-item-icon-no-tooltip;
}
&:hover,
&.is-active {
background: @at-color-side-nav-item-background-hover;
@ -201,7 +201,6 @@
height: 100%;
width: 100%;
flex-direction: column;
padding-left: @at-width-collapsed-side-nav;
padding-bottom: @at-space-4x;
overflow-x: hidden;
}
@ -254,3 +253,44 @@
}
}
}
/* Tower Sub Nav Dropdown */
.at-SettingsSubPane {
position: relative;
}
.at-SettingsSubPane-content {
display: none;
position: absolute;
background-color: @at-gray-848992;
min-width: 140px;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
bottom: 0px;
left: @at-width-collapsed-side-nav;
z-index: 2000;
}
.at-Layout-side--expanded + .at-SettingsSubPane {
.at-SettingsSubPane-content {
left: @at-width-expanded-side-nav;
}
}
.at-SettingsSubPane-content a {
color: @at-white;
font-size: 13px;
padding: 10px 20px;
text-decoration: none;
display: block;
height: 39px;
}
// hover stuff
.at-SettingsSubPane-content a:hover {
background-color: @at-gray-b7;
}
.at-SettingsSubPane.at-SettingsSubPane--visible .at-SettingsSubPane-content {
display: block;
}
.at-SettingsSubPane.at-SettingsSubPane--visible .nav-button {
background-color: @at-gray-b7;
}

View File

@ -1,8 +1,12 @@
import defaultStrings from '~assets/default.strings.json';
const templateUrl = require('~components/layout/layout.partial.html');
function AtLayoutController ($scope, $http, strings, ProcessErrors, $transitions) {
const vm = this || {};
vm.product = defaultStrings.BRAND_NAME;
$transitions.onSuccess({}, (transition) => {
vm.currentState = transition.to().name;
});

View File

@ -95,8 +95,8 @@
<at-side-nav-item icon-class="fa-cubes" route="applications" name="APPLICATIONS"
ng-show="$parent.layoutVm.isSuperUser || $parent.layoutVm.isOrgAdmin">
</at-side-nav-item>
<at-side-nav-item icon-class="fa-cog" route="configuration" name="SETTINGS"
system-admin-only="true">
<at-side-nav-item icon-class="fa-cog" route="settings" name="SETTINGS"
system-admin-only="true" show-settings-sub-menu="true" no-tooltip-on-collapsed="true">
</at-side-nav-item>
</at-side-nav>
<div class="at-Layout-main" ng-class="{'at-Layout-main--noLicense': vm.licenseIsMissing}">

View File

@ -2,6 +2,20 @@ const templateUrl = require('~components/layout/side-nav-item.partial.html');
function atSideNavItemLink (scope, element, attrs, ctrl) {
[scope.navVm, scope.layoutVm] = ctrl;
if (attrs.showSettingsSubMenu) {
element.hover(() => {
scope.navVm.onSettingsNavItem = true;
scope.navVm.showSettingsSubMenu = true;
}, () => {
scope.navVm.onSettingsNavItem = false;
setTimeout(() => {
if (!scope.navVm.onSettingsSubPane) {
scope.navVm.showSettingsSubMenu = false;
}
}, 100);
});
}
}
function AtSideNavItemController ($scope, strings) {
@ -42,11 +56,13 @@ function atSideNavItem () {
controller: AtSideNavItemController,
controllerAs: 'vm',
link: atSideNavItemLink,
transclude: true,
scope: {
iconClass: '@',
name: '@',
route: '@',
systemAdminOnly: '@'
systemAdminOnly: '@',
noTooltipOnCollapsed: '@'
}
};
}

View File

@ -1,9 +1,10 @@
<a class="at-Layout-sideNavItem" ui-sref="{{ route }}" ng-class="{'is-active': vm.isRoute}"
ng-show="(!systemAdminOnly || layoutVm.isSuperUser) && layoutVm.isLoggedIn &&
!layoutVm.licenseIsMissing">
<at-popover state="vm.tooltip" ng-if="!navVm.isExpanded"></at-popover>
<at-popover ng-if="!noTooltipOnCollapsed && !navVm.isExpanded" state="vm.tooltip"></at-popover>
<i class="fa {{ iconClass }}" ng-show="navVm.isExpanded"></i>
<i class="fa {{ iconClass }}" ng-class="{'is-no-tooltip': noTooltipOnCollapsed}"
ng-show="noTooltipOnCollapsed || navVm.isExpanded"></i>
<span class="at-Layout-sideNavItemName" ng-show="navVm.isExpanded">
{{ layoutVm.getString(name) }}
</span>

View File

@ -10,6 +10,17 @@ function atSideNavLink (scope, element, attrs, ctrl) {
scope.$emit('clickOutsideSideNav');
}
});
element.find('.at-SettingsSubPane').hover(() => {
scope.vm.onSettingsSubPane = true;
}, () => {
scope.vm.onSettingsSubPane = false;
setTimeout(() => {
if (!scope.vm.onSettingsNavItem) {
scope.vm.showSettingsSubMenu = false;
}
}, 100);
});
}
function AtSideNavController ($scope, $window) {

View File

@ -1,8 +1,18 @@
<div class="at-Layout-side"
ng-class="{'at-Layout-side--expanded': vm.isExpanded && layoutVm.isLoggedIn}" ng-show="layoutVm.isLoggedIn && !layoutVm.licenseIsMissing">
<div class="at-Layout-sideNavItem at-Layout-sideNavToggle" ng-click="vm.toggleExpansion()"
ng-show="layoutVm.isLoggedIn && !layoutVm.licenseIsMissing">
<i class="fa fa-bars"></i>
<div class="at-Layout-sideContainer" ng-show="layoutVm.isLoggedIn && !layoutVm.licenseIsMissing">
<div class="at-Layout-side" ng-class="{'at-Layout-side--expanded': vm.isExpanded && layoutVm.isLoggedIn}">
<div class="at-Layout-sideNavItem at-Layout-sideNavToggle" ng-click="vm.toggleExpansion()"
ng-show="layoutVm.isLoggedIn && !layoutVm.licenseIsMissing">
<i class="fa fa-bars"></i>
</div>
<ng-transclude></ng-transclude>
</div>
<div class="at-SettingsSubPane" ng-class="{'at-SettingsSubPane--visible': vm.showSettingsSubMenu}">
<div class="at-SettingsSubPane-content">
<a ui-sref="settings.form({form: 'auth'})">Authentication</a>
<a ui-sref="settings.form({form: 'jobs'})">Jobs</a>
<a ui-sref="settings.form({form: 'system'})">System</a>
<a ui-sref="settings.form({form: 'ui'})">User Interface</a>
<a ui-sref="settings.form({form: 'license'})" ng-if="vm.product === 'Tower'">License</a>
</div>
</div>
<ng-transclude></ng-transclude>
</div>

View File

@ -238,6 +238,7 @@
@at-padding-left-side-nav-toggle-icon: 15px;
@at-padding-left-side-nav-item-icon: 10px;
@at-padding-left-side-nav-item-icon-expanded: 15px;
@at-padding-left-side-nav-item-icon-no-tooltip: 18px;
@at-padding-between-side-nav-icon-text: @at-space-3x;
@at-padding-list-empty: @at-space-2x;
@at-padding-list-row-item-tag: 3px 9px;

View File

@ -65,7 +65,7 @@
@import '../../src/activity-stream/streamDetailModal/streamDetailModal.block.less';
@import '../../src/activity-stream/activitystream.block.less';
@import '../../src/bread-crumb/bread-crumb.block.less';
@import '../../src/configuration/configuration.block.less';
@import '../../src/configuration/settings.block.less';
@import '../../src/credentials/ownerList.block.less';
@import '../../src/home/dashboard/counts/dashboard-counts.block.less';
@import '../../src/home/dashboard/graphs/dashboard-graphs.block.less';
@ -128,7 +128,6 @@
@import '../../src/workflow-results/workflow-status-bar/workflow-status-bar.block.less';
@import '../../src/workflow-results/workflow-results.block.less';
/**
* App-wide style
*

View File

@ -54,14 +54,14 @@ export default function BuildAnchor($log, $filter) {
case 'setting':
if (activity.summary_fields.setting[0].category === 'jobs' ||
activity.summary_fields.setting[0].category === 'ui') {
url += `configuration/${activity.summary_fields.setting[0].category}`;
url += `settings/${activity.summary_fields.setting[0].category}`;
}
else if (activity.summary_fields.setting[0].category === 'system' ||
activity.summary_fields.setting[0].category === 'logging') {
url += `configuration/system`;
url += `settings/system`;
}
else {
url += `configuration/auth`;
url += `settings/auth`;
}
break;
case 'notification_template':

View File

@ -1,61 +0,0 @@
<div class="Section-messageBar" ng-if="vm.show_auditor_bar">
<i class="fa fa-warning"></i>
<span translate>System auditors have read-only permissions in this section.</span>
<button class="Section-messageBar--close" ng-click="vm.closeMessageBar()"><i class="fa fa-times-circle"></i></button>
</div>
<div class="tab-pane" id="configuration-panel">
<div ng-cloak id="htmlTemplate" class="Panel">
<div class="Form-header">
<div class="Form-title Form-title--uppercase" translate>CONFIGURE {{ BRAND_NAME }}</div>
</div>
<div class="row Form-tabRow">
<div class="col-lg-12">
<div class="Form-tabHolder"ng-class="{'Form-tabHolder--licenseSelected': vm.activeTab === 'license'}">
<div id="auth_tab"
class="Form-tab"
ng-click="vm.activeTabCheck('auth')"
ng-class="{'is-selected': vm.activeTab === 'auth' }"
translate>
Authentication
</div>
<div id="jobs_tab"
class="Form-tab"
ng-click="vm.activeTabCheck('jobs')"
ng-class="{'is-selected': vm.activeTab === 'jobs' }"
translate>
Jobs
</div>
<div id="system_tab"
class="Form-tab"
ng-click="vm.activeTabCheck('system')"
ng-class="{'is-selected': vm.activeTab === 'system' }"
translate>
System
</div>
<div id="ui_tab"
class="Form-tab"
ng-click="vm.activeTabCheck('ui')"
ng-class="{'is-selected': vm.activeTab === 'ui' }"
translate>
User Interface
</div>
<div id="license_tab"
class="Form-tab"
ng-show="vm.product === 'Tower'"
ng-click="vm.activeTabCheck('license')"
ng-class="{'is-selected': vm.activeTab === 'license' }"
translate>
License
</div>
</div>
</div>
</div>
<div ui-view="auth" ng-show="vm.activeTab === 'auth'"></div>
<div ui-view="jobs" ng-show="vm.activeTab === 'jobs'"></div>
<div ui-view="system" ng-show="vm.activeTab === 'system'"></div>
<div ui-view="ui" ng-show="vm.activeTab === 'ui'"></div>
<div ui-view="license" ng-show="vm.product === 'Tower' && vm.activeTab === 'license'"></div>
<div id="FormModal-dialog"></div>
</div>
</div>

View File

@ -1,62 +0,0 @@
/*************************************************
* Copyright (c) 2016 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
import {templateUrl} from '../shared/template-url/template-url.factory';
import ConfigurationController from './configuration.controller';
import { N_ } from '../i18n';
// Import form controllers
import ConfigurationAuthController from './auth-form/configuration-auth.controller';
import ConfigurationJobsController from './jobs-form/configuration-jobs.controller';
import ConfigurationSystemController from './system-form/configuration-system.controller';
import ConfigurationUiController from './ui-form/configuration-ui.controller';
export default {
name: 'configuration',
route: '/configuration/:currentTab',
params: {
currentTab: {
value: 'auth',
dynamic: true,
isOptional: true
}
},
ncyBreadcrumb: {
label: N_("EDIT CONFIGURATION")
},
resolve: {
configDataResolve: ['ConfigurationService', function(ConfigurationService){
return ConfigurationService.getConfigurationOptions();
}]
},
views: {
'': {
templateUrl: templateUrl('configuration/configuration'),
controller: ConfigurationController,
controllerAs: 'vm'
},
'auth@configuration': {
templateUrl: templateUrl('configuration/auth-form/configuration-auth'),
controller: ConfigurationAuthController,
controllerAs: 'authVm'
},
'jobs@configuration': {
templateUrl: templateUrl('configuration/jobs-form/configuration-jobs'),
controller: ConfigurationJobsController,
controllerAs: 'jobsVm'
},
'system@configuration': {
templateUrl: templateUrl('configuration/system-form/configuration-system'),
controller: ConfigurationSystemController,
controllerAs: 'systemVm'
},
'ui@configuration': {
templateUrl: templateUrl('configuration/ui-form/configuration-ui'),
controller: ConfigurationUiController,
controllerAs: 'uiVm'
},
},
};

View File

@ -7,84 +7,44 @@
export default [
'$scope',
'$rootScope',
'$state',
'$stateParams',
'$timeout',
'$q',
'configurationAzureForm',
'configurationGithubForm',
'configurationGithubOrgForm',
'configurationGithubTeamForm',
'configurationGoogleForm',
'configurationLdapForm',
'configurationLdap1Form',
'configurationLdap2Form',
'configurationLdap3Form',
'configurationLdap4Form',
'configurationLdap5Form',
'configurationRadiusForm',
'configurationTacacsForm',
'configurationSamlForm',
'ConfigurationService',
'ConfigurationUtils',
'SettingsUtils',
'CreateSelect2',
'GenerateForm',
'i18n',
'ParseTypeChange',
function(
function (
$scope,
$rootScope,
$state,
$stateParams,
$timeout,
$q,
configurationAzureForm,
configurationGithubForm,
configurationGithubOrgForm,
configurationGithubTeamForm,
configurationGoogleForm,
configurationLdapForm,
configurationLdap1Form,
configurationLdap2Form,
configurationLdap3Form,
configurationLdap4Form,
configurationLdap5Form,
configurationRadiusForm,
configurationTacacsForm,
configurationSamlForm,
ConfigurationService,
ConfigurationUtils,
SettingsUtils,
CreateSelect2,
GenerateForm,
i18n,
ParseTypeChange
) {
var authVm = this;
const authVm = this;
const generator = GenerateForm;
const formTracker = $scope.$parent.vm.formTracker; // track the current active form
var generator = GenerateForm;
var formTracker = $scope.$parent.vm.formTracker;
var dropdownValue = 'azure';
var activeAuthForm = 'azure';
var ldapDropdownValue = '';
authVm.activeAuthForm = 'azure';
authVm.activeTab = 'azure';
authVm.ldapDropdownValue = '';
authVm.githubDropdownValue = 'github';
let codeInputInitialized = false;
// Default active form
if ($stateParams.currentTab === '' || $stateParams.currentTab === 'auth') {
formTracker.setCurrentAuth(activeAuthForm);
const formDefs = $scope.$parent.formDefs;
// Default active authform
if ($stateParams.form === 'auth') {
formTracker.setCurrentAuth(authVm.activeAuthForm);
}
const getActiveAuthForm = () => {
if (authVm.dropdownValue === 'ldap') {
return `ldap${authVm.ldapDropdownValue}`;
}
return authVm.dropdownValue;
};
const activeForm = function(revertDropdown) {
authVm.activeForm = function(tab) {
if(!_.get($scope.$parent, [formTracker.currentFormName(), '$dirty'])) {
authVm.activeAuthForm = getActiveAuthForm();
authVm.activeTab = tab;
authVm.activeAuthForm = getActiveAuthForm(tab);
formTracker.setCurrentAuth(authVm.activeAuthForm);
startCodeMirrors();
} else {
@ -97,7 +57,8 @@ export default [
onClick: function() {
$scope.$parent.vm.populateFromApi();
$scope.$parent[formTracker.currentFormName()].$setPristine();
authVm.activeAuthForm = getActiveAuthForm();
authVm.activeTab = tab;
authVm.activeAuthForm = getActiveAuthForm(tab);
formTracker.setCurrentAuth(authVm.activeAuthForm);
$('#FormModal-dialog').dialog('close');
}
@ -108,15 +69,13 @@ export default [
.then(function() {
$scope.$parent[formTracker.currentFormName()].$setPristine();
$scope.$parent.vm.populateFromApi();
authVm.activeAuthForm = getActiveAuthForm();
authVm.activeTab = tab;
authVm.activeAuthForm = getActiveAuthForm(tab);
formTracker.setCurrentAuth(authVm.activeAuthForm);
$('#FormModal-dialog').dialog('close');
}).catch(() => {
event.preventDefault();
$('#FormModal-dialog').dialog('close');
if (revertDropdown) {
revertDropdown();
}
});
},
"class": "btn btn-primary",
@ -128,31 +87,9 @@ export default [
authVm.ldapSelected = (authVm.activeAuthForm.indexOf('ldap') !== -1);
};
const changeAuthDropdown = (previousVal) => {
activeForm(() => {
authVm.dropdownValue = previousVal;
CreateSelect2({
element: '#configure-dropdown-nav',
multiple: false,
});
});
};
const changeLdapDropdown = (previousVal) => {
activeForm(() => {
authVm.ldapDropdownValue = previousVal;
CreateSelect2({
element: '#configure-ldap-dropdown',
multiple: false,
});
});
};
var dropdownOptions = [
authVm.dropdownOptions = [
{label: i18n._('Azure AD'), value: 'azure'},
{label: i18n._('GitHub'), value: 'github'},
{label: i18n._('GitHub Org'), value: 'github_org'},
{label: i18n._('GitHub Team'), value: 'github_team'},
{label: i18n._('Google OAuth2'), value: 'google_oauth'},
{label: i18n._('LDAP'), value: 'ldap'},
{label: i18n._('RADIUS'), value: 'radius'},
@ -160,7 +97,7 @@ export default [
{label: i18n._('TACACS+'), value: 'tacacs'}
];
var ldapDropdownOptions = [
authVm.ldapDropdownOptions = [
{label: i18n._('Default'), value: ''},
{label: i18n._('LDAP 1 (Optional)'), value: '1'},
{label: i18n._('LDAP 2 (Optional)'), value: '2'},
@ -169,6 +106,12 @@ export default [
{label: i18n._('LDAP 5 (Optional)'), value: '5'},
];
authVm.githubDropdownOptions = [
{label: i18n._('GitHub (Default)'), value: 'github'},
{label: i18n._('GitHub Org'), value: 'github_org'},
{label: i18n._('GitHub Team'), value: 'github_team'},
];
CreateSelect2({
element: '#configure-dropdown-nav',
multiple: false,
@ -179,74 +122,79 @@ export default [
multiple: false,
});
CreateSelect2({
element: '#configure-github-dropdown',
multiple: false,
});
var authForms = [
{
formDef: configurationAzureForm,
formDef: formDefs.azure,
id: 'auth-azure-form',
name: 'azure'
},
{
formDef: configurationGithubForm,
formDef: formDefs.github,
id: 'auth-github-form',
name: 'github'
},
{
formDef: configurationGithubOrgForm,
formDef: formDefs.github_org,
id: 'auth-github-org-form',
name: 'github_org'
},
{
formDef: configurationGithubTeamForm,
formDef: formDefs.github_team,
id: 'auth-github-team-form',
name: 'github_team'
},
{
formDef: configurationGoogleForm,
formDef: formDefs.google_oauth,
id: 'auth-google-form',
name: 'google_oauth'
},
{
formDef: configurationRadiusForm,
formDef: formDefs.radius,
id: 'auth-radius-form',
name: 'radius'
},
{
formDef: configurationTacacsForm,
formDef: formDefs.tacacs,
id: 'auth-tacacs-form',
name: 'tacacs'
},
{
formDef: configurationSamlForm,
formDef: formDefs.saml,
id: 'auth-saml-form',
name: 'saml'
},
{
formDef: configurationLdapForm,
formDef: formDefs.ldap,
id: 'auth-ldap-form',
name: 'ldap'
},
{
formDef: configurationLdap1Form,
formDef: formDefs.ldap1,
id: 'auth-ldap1-form',
name: 'ldap1'
},
{
formDef: configurationLdap2Form,
formDef: formDefs.ldap2,
id: 'auth-ldap2-form',
name: 'ldap2'
},
{
formDef: configurationLdap3Form,
formDef: formDefs.ldap3,
id: 'auth-ldap3-form',
name: 'ldap3'
},
{
formDef: configurationLdap4Form,
formDef: formDefs.ldap4,
id: 'auth-ldap4-form',
name: 'ldap4'
},
{
formDef: configurationLdap5Form,
formDef: formDefs.ldap5,
id: 'auth-ldap5-form',
name: 'ldap5'
},
@ -256,11 +204,11 @@ export default [
_.each(forms, function(form) {
var keys = _.keys(form.fields);
_.each(keys, function(key) {
if($scope.$parent.configDataResolve[key].type === 'choice') {
if($scope.configDataResolve[key].type === 'choice') {
// Create options for dropdowns
var optionsGroup = key + '_options';
$scope.$parent[optionsGroup] = [];
_.each($scope.$parent.configDataResolve[key].choices, function(choice){
_.each($scope.configDataResolve[key].choices, function(choice){
$scope.$parent[optionsGroup].push({
name: choice[0],
label: choice[1],
@ -274,15 +222,28 @@ export default [
form.buttons.save.disabled = $rootScope.user_is_system_auditor;
});
function startCodeMirrors(key) {
$scope.$parent.$parent.parseType = 'json';
_.each(authForms, function(form) {
// Generate the forms
generator.inject(form.formDef, {
id: form.id,
mode: 'edit',
scope: $scope.$parent.$parent,
related: true,
noPanel: true
});
});
function startCodeMirrors (key) {
var form = _.find(authForms, f => f.name === $scope.authVm.activeAuthForm);
if(!key){
// Attach codemirror to fields that need it
_.each(form.formDef.fields, function(field) {
// Codemirror balks at empty values so give it one
if($scope.$parent[field.name] === null && field.codeMirror) {
$scope.$parent[field.name] = '{}';
if($scope.$parent.$parent[field.name] === null && field.codeMirror) {
$scope.$parent.$parent[field.name] = '{}';
}
if(field.codeMirror) {
createIt(field.name);
@ -295,11 +256,11 @@ export default [
function createIt(name){
ParseTypeChange({
scope: $scope.$parent,
scope: $scope.$parent.$parent,
variable: name,
parse_variable: 'parseType',
field_id: form.formDef.name + '_' + name,
readOnly: $scope.$parent.configDataResolve[name] && $scope.$parent.configDataResolve[name].disabled ? true : false
readOnly: $scope.configDataResolve[name] && $scope.configDataResolve[name].disabled ? true : false
});
$scope.parseTypeChange('parseType', name);
}
@ -307,35 +268,22 @@ export default [
function addFieldInfo(form, key) {
_.extend(form.fields[key], {
awPopOver: ($scope.$parent.configDataResolve[key].defined_in_file) ?
null: $scope.$parent.configDataResolve[key].help_text,
label: $scope.$parent.configDataResolve[key].label,
awPopOver: ($scope.configDataResolve[key].defined_in_file) ?
null: $scope.configDataResolve[key].help_text,
label: $scope.configDataResolve[key].label,
name: key,
toggleSource: key,
dataPlacement: 'top',
placeholder: ConfigurationUtils.formatPlaceholder($scope.$parent.configDataResolve[key].placeholder, key) || null,
dataTitle: $scope.$parent.configDataResolve[key].label,
required: $scope.$parent.configDataResolve[key].required,
placeholder: SettingsUtils.formatPlaceholder($scope.configDataResolve[key].placeholder, key) || null,
dataTitle: $scope.configDataResolve[key].label,
required: $scope.configDataResolve[key].required,
ngDisabled: $rootScope.user_is_system_auditor,
disabled: $scope.$parent.configDataResolve[key].disabled || null,
readonly: $scope.$parent.configDataResolve[key].readonly || null,
definedInFile: $scope.$parent.configDataResolve[key].defined_in_file || null
disabled: $scope.configDataResolve[key].disabled || null,
readonly: $scope.configDataResolve[key].readonly || null,
definedInFile: $scope.configDataResolve[key].defined_in_file || null
});
}
$scope.$parent.parseType = 'json';
_.each(authForms, function(form) {
// Generate the forms
generator.inject(form.formDef, {
id: form.id,
mode: 'edit',
scope: $scope.$parent,
related: true,
noPanel: true
});
});
// Flag to avoid re-rendering and breaking Select2 dropdowns on tab switching
var dropdownRendered = false;
@ -409,7 +357,7 @@ export default [
});
$scope.$on('populated', function() {
let tab = $stateParams.currentTab;
let tab = $stateParams.form;
if (tab === 'auth') {
startCodeMirrors();
@ -427,23 +375,24 @@ export default [
});
$scope.$on('codeMirror_populated', function() {
let tab = $stateParams.currentTab;
let tab = $stateParams.form;
if (tab === 'auth') {
startCodeMirrors();
codeInputInitialized = true;
}
});
function getActiveAuthForm (tab) {
if (tab === 'ldap') {
return `ldap${authVm.ldapDropdownValue}`;
} else if (tab === 'github') {
return authVm.githubDropdownValue;
}
return tab;
}
angular.extend(authVm, {
changeAuthDropdown: changeAuthDropdown,
changeLdapDropdown: changeLdapDropdown,
activeAuthForm: activeAuthForm,
authForms: authForms,
dropdownOptions: dropdownOptions,
dropdownValue: dropdownValue,
ldapDropdownValue: ldapDropdownValue,
ldapDropdownOptions: ldapDropdownOptions,
});
}
];

View File

@ -1,19 +1,20 @@
<div class="tab-pane Configuration-container" id="configuration_edit">
<div class="Form-nav--dropdownContainer">
<div class="Form-nav--dropdownLabel" translate>Sub Category</div>
<div class="Form-nav--dropdown">
<select
id="configure-dropdown-nav"
class="form-control"
ng-model="authVm.dropdownValue"
ng-options="opt.value as opt.label for opt in authVm.dropdownOptions"
ng-change="authVm.changeAuthDropdown('{{authVm.dropdownValue}}')">
</select>
<div class="row Form-tabRow">
<div class="col-lg-12">
<div class="Form-tabHolder">
<div ng-repeat="opt in authVm.dropdownOptions"
class="Form-tab"
ng-click="authVm.activeForm(opt.value)"
ng-class="{'is-selected': authVm.activeTab === opt.value }"
translate>
{{opt.label}}
</div>
</div>
</div>
</div>
<div class="Form-nav--ldapDropdownContainer" ng-show="authVm.dropdownValue === 'ldap'">
<div class="Form-nav--dropdownContainer" ng-show="authVm.activeTab === 'ldap'">
<div class="Form-nav--dropdownLabel" translate>LDAP Server</div>
<div class="Form-nav--dropdown">
<select
@ -21,12 +22,23 @@
class="form-control"
ng-model="authVm.ldapDropdownValue"
ng-options="opt.value as opt.label for opt in authVm.ldapDropdownOptions"
ng-change="authVm.changeLdapDropdown('{{authVm.ldapDropdownValue}}')">
ng-change="authVm.activeForm('ldap')">
</select>
</div>
</div>
<hr ng-show="authVm.dropdownValue === 'ldap'"/>
<div class="Form-nav--dropdownContainer" ng-show="authVm.activeTab === 'github'">
<div class="Form-nav--dropdownLabel" translate>GitHub Category</div>
<div class="Form-nav--dropdown">
<select
id="configure-github-dropdown"
class="form-control"
ng-model="authVm.githubDropdownValue"
ng-options="opt.value as opt.label for opt in authVm.githubDropdownOptions"
ng-change="authVm.activeForm('github')">
</select>
</div>
</div>
<div class="row">
<div class="col-lg-12">

View File

@ -7,12 +7,8 @@
export default [
'$scope',
'$rootScope',
'$state',
'$stateParams',
'$timeout',
'ConfigurationJobsForm',
'ConfigurationService',
'ConfigurationUtils',
'CreateSelect2',
'GenerateForm',
'ParseTypeChange',
@ -20,26 +16,27 @@ export default [
function(
$scope,
$rootScope,
$state,
$stateParams,
$timeout,
ConfigurationJobsForm,
ConfigurationService,
ConfigurationUtils,
CreateSelect2,
GenerateForm,
ParseTypeChange,
i18n
) {
var generator = GenerateForm;
const generator = GenerateForm;
var form = ConfigurationJobsForm;
const formTracker = $scope.$parent.vm.formTracker;
if ($stateParams.form === 'jobs') {
formTracker.setCurrentAuth('jobs');
}
let tab;
let codeInputInitialized = false;
$scope.$parent.AD_HOC_COMMANDS_options = [];
_.each($scope.$parent.configDataResolve.AD_HOC_COMMANDS.default, function(command) {
$scope.$parent.AD_HOC_COMMANDS_options.push({
$scope.$parent.$parent.AD_HOC_COMMANDS_options = [];
_.each($scope.$parent.configDataResolve.AD_HOC_COMMANDS.default, function (command) {
$scope.$parent.$parent.AD_HOC_COMMANDS_options.push({
name: command,
label: command,
value: command
@ -74,18 +71,20 @@ export default [
generator.inject(form, {
id: 'configure-jobs-form',
mode: 'edit',
scope: $scope.$parent,
scope: $scope.$parent.$parent,
related: false,
noPanel: true
});
$scope.$parent.$parent.parseType = 'json';
function initializeCodeInput () {
let name = 'AWX_TASK_ENV';
ParseTypeChange({
scope: $scope.$parent,
scope: $scope.$parent.$parent,
variable: name,
parseType: 'application/json',
parse_variable: 'parseType',
field_id: `configuration_jobs_template_${name}`
});
@ -93,15 +92,14 @@ export default [
}
function loadAdHocCommands () {
$scope.$parent.AD_HOC_COMMANDS_values = $scope.$parent.AD_HOC_COMMANDS.map(value => value);
$scope.$parent.AD_HOC_COMMANDS = $scope.$parent.AD_HOC_COMMANDS.map(value => ({
$scope.$parent.$parent.AD_HOC_COMMANDS_values = $scope.$parent.$parent.AD_HOC_COMMANDS.map(value => value);
$scope.$parent.$parent.AD_HOC_COMMANDS = $scope.$parent.$parent.AD_HOC_COMMANDS.map(value => ({
value,
name: value,
label: value
}));
$scope.$parent.AD_HOC_COMMANDS_options = $scope.$parent.AD_HOC_COMMANDS.map(tag => tag);
$scope.$parent.$parent.AD_HOC_COMMANDS_options = $scope.$parent.$parent.AD_HOC_COMMANDS.map(tag => tag);
CreateSelect2({
element: '#configuration_jobs_template_AD_HOC_COMMANDS',
multiple: true,
@ -112,7 +110,7 @@ export default [
}
function revertAdHocCommands () {
$scope.$parent.AD_HOC_COMMANDS = $scope.$parent.configDataResolve.AD_HOC_COMMANDS.default.map(value => ({
$scope.$parent.$parent.AD_HOC_COMMANDS = $scope.$parent.configDataResolve.AD_HOC_COMMANDS.default.map(value => ({
value,
name: value,
label: value
@ -125,60 +123,36 @@ export default [
}
});
$scope.$parent.AD_HOC_COMMANDS_options = $scope.$parent.AD_HOC_COMMANDS.map(tag => tag);
$scope.$parent.AD_HOC_COMMANDS_values = $scope.$parent.AD_HOC_COMMANDS.map(tag => tag.value);
$scope.$parent.$parent.AD_HOC_COMMANDS_options = $scope.$parent.$parent.AD_HOC_COMMANDS.map(tag => tag);
$scope.$parent.$parent.AD_HOC_COMMANDS_values = $scope.$parent.$parent.AD_HOC_COMMANDS.map(tag => tag.value);
CreateSelect2({
element: '#configuration_jobs_template_AD_HOC_COMMANDS',
multiple: true,
addNew: true,
placeholder: i18n._('Select commands'),
options: $scope.$parent.AD_HOC_COMMANDS_options
options: $scope.$parent.$parent.AD_HOC_COMMANDS_options
});
}
// Fix for bug where adding selected opts causes form to be $dirty and triggering modal
// TODO Find better solution for this bug
$timeout(function(){
$scope.$parent.configuration_jobs_template_form.$setPristine();
}, 1000);
// Managing the state of select2's tags since the behavior is unpredictable otherwise.
let commandsElement = $('#configuration_jobs_template_AD_HOC_COMMANDS');
commandsElement.on('select2:select', event => {
let command = event.params.data.text;
let commands = $scope.$parent.AD_HOC_COMMANDS_values;
let commands = $scope.$parent.$parent.AD_HOC_COMMANDS_values;
commands.push(command);
});
commandsElement.on('select2:unselect', event => {
let command = event.params.data.text;
let commands = $scope.$parent.AD_HOC_COMMANDS_values;
let commands = $scope.$parent.$parent.AD_HOC_COMMANDS_values;
$scope.$parent.AD_HOC_COMMANDS_values = commands.filter(value => value !== command);
$scope.$parent.$parent.AD_HOC_COMMANDS_values = commands.filter(value => value !== command);
});
$scope.$on('AD_HOC_COMMANDS_reverted', () => revertAdHocCommands());
/*
* Controllers for each tab are initialized when configuration is opened. A listener
* on the URL itself is necessary to determine which tab is active. If a non-active
* tab initializes a codemirror, it doesn't display properly until the user navigates
* to the tab and it's been clicked.
*/
$scope.$on('$locationChangeStart', (event, url) => {
let parts = url.split('/');
tab = parts[parts.length - 1];
if (tab === 'jobs' && !codeInputInitialized) {
initializeCodeInput();
codeInputInitialized = true;
}
});
/*
* Necessary to listen for revert clicks and relaunch the codemirror instance.
*/
@ -194,8 +168,7 @@ export default [
* direct load of this tab or if the user comes from a different tab.
*/
$scope.$on('populated', () => {
tab = $stateParams.currentTab;
tab = $stateParams.form;
if (tab === 'jobs') {
initializeCodeInput();
codeInputInitialized = true;

View File

@ -1,6 +1,4 @@
<div class="tab-pane Configuration-container" id="configuration_edit">
<!-- <div ui-view="form"></div>
<div ng-cloak id="htmlTemplate"> -->
<div class="row">
<div class="col-lg-12">
<div id="configure-jobs-form"></div>

View File

@ -1,14 +1,9 @@
/*************************************************
* Copyright (c) 2015 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
import defaultStrings from '~assets/default.strings.json';
export default [
'$scope', '$rootScope', '$state', '$stateParams', '$timeout', '$q', 'Alert',
'ConfigurationService', 'ConfigurationUtils', 'CreateDialog', 'CreateSelect2', 'i18n', 'ParseTypeChange', 'ProcessErrors', 'Store',
'Wait', 'configDataResolve', 'ToJSON', 'ConfigService', 'ngToast',
'$scope', '$rootScope', '$state', '$stateParams', '$q',
'SettingsService', 'SettingsUtils', 'CreateDialog', 'i18n', 'ProcessErrors', 'Store',
'Wait', 'configDataResolve', 'ToJSON', 'ConfigService',
//Form definitions
'configurationAzureForm',
'configurationGithubForm',
@ -29,10 +24,11 @@ export default [
'systemMiscForm',
'ConfigurationJobsForm',
'ConfigurationUiForm',
'ngToast',
function(
$scope, $rootScope, $state, $stateParams, $timeout, $q, Alert,
ConfigurationService, ConfigurationUtils, CreateDialog, CreateSelect2, i18n, ParseTypeChange, ProcessErrors, Store,
Wait, configDataResolve, ToJSON, ConfigService, ngToast,
$scope, $rootScope, $state, $stateParams, $q,
SettingsService, SettingsUtils, CreateDialog, i18n, ProcessErrors, Store,
Wait, configDataResolve, ToJSON, ConfigService,
//Form definitions
configurationAzureForm,
configurationGithubForm,
@ -52,13 +48,15 @@ export default [
systemLoggingForm,
systemMiscForm,
ConfigurationJobsForm,
ConfigurationUiForm
ConfigurationUiForm,
ngToast
) {
var vm = this;
const vm = this;
vm.product = defaultStrings.BRAND_NAME;
vm.activeTab = $stateParams.form;
var formDefs = {
const formDefs = {
'azure': configurationAzureForm,
'github': configurationGithubForm,
'github_org': configurationGithubOrgForm,
@ -80,8 +78,19 @@ export default [
'ui': ConfigurationUiForm
};
$scope.configDataResolve = configDataResolve;
$scope.formDefs = formDefs;
// check if it's auditor, show messageBar
$scope.show_auditor_bar = false;
if($rootScope.user_is_system_auditor && Store('show_auditor_bar') !== false) {
$scope.show_auditor_bar = true;
} else {
$scope.show_auditor_bar = false;
}
var populateFromApi = function() {
ConfigurationService.getCurrentValues()
SettingsService.getCurrentValues()
.then(function(data) {
var currentKeys = _.keys(data);
$scope.requiredLogValues = {};
@ -113,12 +122,12 @@ export default [
} else if (isLdapUserSearch || isLdapGroupSearch) {
$scope[key] = JSON.stringify(data[key]);
} else {
$scope[key] = ConfigurationUtils.arrayToList(data[key], key);
$scope[key] = SettingsUtils.arrayToList(data[key], key);
}
} else {
//handle nested objects
if(ConfigurationUtils.isEmpty(data[key])) {
if(SettingsUtils.isEmpty(data[key])) {
$scope[key] = '{}';
} else {
$scope[key] = JSON.stringify(data[key]);
@ -172,31 +181,6 @@ export default [
},
};
// Default to auth form and tab
if ($stateParams.currentTab === '') {
$state.go('configuration', {
currentTab: 'auth'
}, {
location: true,
inherit: false,
notify: false,
reload: false
});
}
var currentForm = '';
var currentTab = function() {
if ($stateParams.currentTab === '' || $stateParams.currentTab === 'auth') {
return 'auth';
} else if ($stateParams.currentTab !== '' && $stateParams.currentTab !== 'auth') {
formTracker.setCurrent($stateParams.currentTab);
return $stateParams.currentTab;
}
};
var activeTab = currentTab();
$scope.configDataResolve = configDataResolve;
var triggerModal = function(msg, title, buttons) {
if ($scope.removeModalReady) {
$scope.removeModalReady();
@ -221,127 +205,6 @@ export default [
});
};
function activeTabCheck(setForm) {
if(!$scope[formTracker.currentFormName()] || !$scope[formTracker.currentFormName()].$dirty) {
active(setForm);
} else {
var msg = i18n._('You have unsaved changes. Would you like to proceed <strong>without</strong> saving?');
var title = i18n._('Warning: Unsaved Changes');
var buttons = [{
label: i18n._("Discard changes"),
"class": "btn Form-cancelButton",
"id": "formmodal-cancel-button",
onClick: function() {
clearApiErrors();
populateFromApi();
$scope[formTracker.currentFormName()].$setPristine();
$('#FormModal-dialog').dialog('close');
active(setForm);
}
}, {
label: i18n._("Save changes"),
onClick: function() {
vm.formSave().then(() => {
$scope[formTracker.currentFormName()].$setPristine();
$('#FormModal-dialog').dialog('close');
active(setForm);
}).catch(()=> {
event.preventDefault();
$('#FormModal-dialog').dialog('close');
});
},
"class": "btn btn-primary",
"id": "formmodal-save-button"
}];
triggerModal(msg, title, buttons);
}
}
function active(setForm) {
// Authentication and System's sub-module dropdowns handled first:
if (setForm === 'auth') {
// Default to 'azure' on first load
if (formTracker.currentAuth === '') {
formTracker.setCurrentAuth('azure');
} else {
// If returning to auth tab reset current form to previously viewed
formTracker.setCurrentAuth(formTracker.currentAuth);
}
} else if (setForm === 'system') {
if (formTracker.currentSystem === '') {
formTracker.setCurrentSystem('misc');
} else {
// If returning to system tab reset current form to previously viewed
formTracker.setCurrentSystem(formTracker.currentSystem);
}
}
vm.activeTab = setForm;
if (setForm !== 'license') {
if (setForm === 'auth') {
formTracker.setCurrentAuth(formTracker.currentAuth);
} else if (setForm === 'system') {
formTracker.setCurrentSystem(formTracker.currentSystem);
} else {
formTracker.setCurrent(setForm);
}
$state.go('configuration', {
currentTab: setForm
}, {
location: true,
inherit: false,
notify: false,
reload: false
});
} else {
$state.go('configuration.license', {
currentTab: setForm
}, {
location: true,
inherit: false,
notify: false,
reload: false
});
}
}
var formCancel = function() {
if ($scope[formTracker.currentFormName()].$dirty === true) {
var msg = i18n._('You have unsaved changes. Would you like to proceed <strong>without</strong> saving?');
var title = i18n._('Warning: Unsaved Changes');
var buttons = [{
label: i18n._("Discard changes"),
"class": "btn Form-cancelButton",
"id": "formmodal-cancel-button",
onClick: function() {
clearApiErrors();
populateFromApi();
$scope[formTracker.currentFormName()].$setPristine();
$('#FormModal-dialog').dialog('close');
}
}, {
label: i18n._("Save changes"),
onClick: function() {
vm.formSave().then(() => {
$scope[formTracker.currentFormName()].$setPristine();
$('#FormModal-dialog').dialog('close');
}).catch(()=> {
event.preventDefault();
$('#FormModal-dialog').dialog('close');
});
},
"class": "btn btn-primary",
"id": "formmodal-save-button"
}];
triggerModal(msg, title, buttons);
} else {
$state.go('setup');
}
};
function loginUpdate() {
// Updates the logo and app config so that logos and info are properly shown
// on logout after modifying.
@ -370,7 +233,7 @@ export default [
Wait('start');
var payload = {};
payload[key] = $scope.configDataResolve[key].default;
ConfigurationService.patchConfiguration(payload)
SettingsService.patchConfiguration(payload)
.then(function() {
$scope[key] = $scope.configDataResolve[key].default;
@ -446,7 +309,6 @@ export default [
var getFormPayload = function() {
var keys = _.keys(formDefs[formTracker.getCurrent()].fields);
var payload = {};
_.each(keys, function(key) {
if($scope.configDataResolve[key].type === 'choice' || multiselectDropdowns.indexOf(key) !== -1) {
//Parse dropdowns and dropdowns labeled as lists
@ -471,10 +333,10 @@ export default [
}
} else if($scope.configDataResolve[key].type === 'list' && $scope[key] !== null) {
// Parse lists
payload[key] = ConfigurationUtils.listToArray($scope[key], key);
payload[key] = SettingsUtils.listToArray($scope[key], key);
}
else if($scope.configDataResolve[key].type === 'nested object') {
if($scope[key] === '') {
if(!$scope[key]) {
payload[key] = {};
} else {
// payload[key] = JSON.parse($scope[key]);
@ -494,11 +356,11 @@ export default [
return payload;
};
var formSave = function() {
vm.formSave = function() {
var saveDeferred = $q.defer();
clearApiErrors();
Wait('start');
ConfigurationService.patchConfiguration(getFormPayload())
SettingsService.patchConfiguration(getFormPayload())
.then(function(data) {
loginUpdate();
@ -532,7 +394,94 @@ export default [
return saveDeferred.promise;
};
vm.formCancel = function() {
if ($scope[formTracker.currentFormName()].$dirty === true) {
var msg = i18n._('You have unsaved changes. Would you like to proceed <strong>without</strong> saving?');
var title = i18n._('Warning: Unsaved Changes');
var buttons = [{
label: i18n._("Discard changes"),
"class": "btn Form-cancelButton",
"id": "formmodal-cancel-button",
onClick: function() {
$('#FormModal-dialog').dialog('close');
$state.go('settings');
}
}, {
label: i18n._("Save changes"),
onClick: function() {
vm.formSave()
.then(function() {
$('#FormModal-dialog').dialog('close');
$state.go('settings');
});
},
"class": "btn btn-primary",
"id": "formmodal-save-button"
}];
triggerModal(msg, title, buttons);
} else {
$state.go('settings');
}
};
vm.resetAllConfirm = function() {
var buttons = [{
label: i18n._("Cancel"),
"class": "btn btn-default",
"id": "formmodal-cancel-button",
onClick: function() {
$('#FormModal-dialog').dialog('close');
}
}, {
label: i18n._("Confirm Reset"),
onClick: function() {
resetAll();
$('#FormModal-dialog').dialog('close');
},
"class": "btn btn-primary",
"id": "formmodal-reset-button"
}];
var msg = i18n._('This will reset all configuration values to their factory defaults. Are you sure you want to proceed?');
var title = i18n._('Confirm factory reset');
triggerModal(msg, title, buttons);
};
vm.closeMessageBar = function() {
var msg = 'Are you sure you want to hide the notification bar?';
var title = 'Warning: Closing notification bar';
var buttons = [{
label: "Cancel",
"class": "btn Form-cancelButton",
"id": "formmodal-cancel-button",
onClick: function() {
$('#FormModal-dialog').dialog('close');
}
}, {
label: "OK",
onClick: function() {
$('#FormModal-dialog').dialog('close');
updateMessageBarPrefs();
},
"class": "btn btn-primary",
"id": "formmodal-save-button"
}];
triggerModal(msg, title, buttons);
};
vm.getCurrentFormTitle = function() {
switch($stateParams.form) {
case 'auth':
return 'AUTHENTICATION';
case 'jobs':
return 'JOBS';
case 'system':
return 'SYSTEM';
case 'ui':
return 'USER INTERFACE';
case 'license':
return 'LICENSE';
}
};
$scope.toggleForm = function(key) {
if($rootScope.user_is_system_auditor) {
@ -545,7 +494,7 @@ export default [
Wait('start');
var payload = {};
payload[key] = $scope[key];
ConfigurationService.patchConfiguration(payload)
SettingsService.patchConfiguration(payload)
.then(function() {
//TODO consider updating form values with returned data here
})
@ -564,7 +513,7 @@ export default [
});
};
var resetAll = function() {
function resetAll () {
var keys = _.keys(formDefs[formTracker.getCurrent()].fields);
var payload = {};
clearApiErrors();
@ -573,7 +522,7 @@ export default [
});
Wait('start');
ConfigurationService.patchConfiguration(payload)
SettingsService.patchConfiguration(payload)
.then(function() {
populateFromApi();
$scope[formTracker.currentFormName()].$setPristine();
@ -610,76 +559,17 @@ export default [
.finally(function() {
Wait('stop');
});
};
var resetAllConfirm = function() {
var buttons = [{
label: i18n._("Cancel"),
"class": "btn btn-default",
"id": "formmodal-cancel-button",
onClick: function() {
$('#FormModal-dialog').dialog('close');
}
}, {
label: i18n._("Confirm Reset"),
onClick: function() {
resetAll();
$('#FormModal-dialog').dialog('close');
},
"class": "btn btn-primary",
"id": "formmodal-reset-button"
}];
var msg = i18n._('This will reset all configuration values to their factory defaults. Are you sure you want to proceed?');
var title = i18n._('Confirm factory reset');
triggerModal(msg, title, buttons);
};
var show_auditor_bar;
if($rootScope.user_is_system_auditor && Store('show_auditor_bar') !== false) {
show_auditor_bar = true;
} else {
show_auditor_bar = false;
}
var updateMessageBarPrefs = function() {
vm.show_auditor_bar = false;
Store('show_auditor_bar', vm.show_auditor_bar);
};
var closeMessageBar = function() {
var msg = 'Are you sure you want to hide the notification bar?';
var title = 'Warning: Closing notification bar';
var buttons = [{
label: "Cancel",
"class": "btn Form-cancelButton",
"id": "formmodal-cancel-button",
onClick: function() {
$('#FormModal-dialog').dialog('close');
}
}, {
label: "OK",
onClick: function() {
$('#FormModal-dialog').dialog('close');
updateMessageBarPrefs();
},
"class": "btn btn-primary",
"id": "formmodal-save-button"
}];
triggerModal(msg, title, buttons);
};
function updateMessageBarPrefs () {
$scope.show_auditor_bar = false;
Store('show_auditor_bar', $scope.show_auditor_bar);
}
angular.extend(vm, {
activeTab: activeTab,
activeTabCheck: activeTabCheck,
closeMessageBar: closeMessageBar,
currentForm: currentForm,
formCancel: formCancel,
formTracker: formTracker,
formSave: formSave,
getFormPayload: getFormPayload,
populateFromApi: populateFromApi,
resetAllConfirm: resetAllConfirm,
show_auditor_bar: show_auditor_bar,
triggerModal: triggerModal,
});
}

View File

@ -0,0 +1,19 @@
<div class="Section-messageBar" ng-if="show_auditor_bar">
<i class="fa fa-warning"></i>
<span translate>System auditors have read-only permissions in this section.</span>
<button class="Section-messageBar--close" ng-click="vm.closeMessageBar()"><i class="fa fa-times-circle"></i></button>
</div>
<div class="tab-pane" id="configuration-panel">
<div ng-cloak id="htmlTemplate" class="Panel">
<div class="Form-header">
<div class="Form-title Form-title--uppercase" translate>{{ vm.getCurrentFormTitle() }}</div>
</div>
<div ui-view="auth" ng-if="vm.activeTab === 'auth'"></div>
<div ui-view="jobs" ng-if="vm.activeTab === 'jobs'"></div>
<div ui-view="system" ng-if="vm.activeTab === 'system'"></div>
<div ui-view="ui" ng-if="vm.activeTab === 'ui'"></div>
<div ui-view="license" ng-show="vm.product === 'Tower' && vm.activeTab === 'license'"></div>
<div id="FormModal-dialog"></div>
</div>
</div>

View File

@ -0,0 +1,56 @@
import {templateUrl} from '../../shared/template-url/template-url.factory';
import { N_ } from '../../i18n';
import SettingsFormController from './settings-form.controller';
// Import form controllers
import SettingsAuthController from './auth-form/configuration-auth.controller';
import SettingsJobsController from './jobs-form/configuration-jobs.controller';
import SettingsSystemController from './system-form/configuration-system.controller';
import SettingsUiController from './ui-form/configuration-ui.controller';
export default {
name: 'settings.form',
route: '/:form',
ncyBreadcrumb: {
label: N_("{{ vm.getCurrentFormTitle() }}")
},
views: {
'@': {
templateUrl: templateUrl('configuration/forms/settings-form'),
controller: SettingsFormController,
controllerAs: 'vm'
},
'auth@settings.form': {
templateUrl: templateUrl('configuration/forms/auth-form/configuration-auth'),
controller: SettingsAuthController,
controllerAs: 'authVm'
},
'jobs@settings.form': {
templateUrl: templateUrl('configuration/forms/jobs-form/configuration-jobs'),
controller: SettingsJobsController,
controllerAs: 'jobsVm'
},
'system@settings.form': {
templateUrl: templateUrl('configuration/forms/system-form/configuration-system'),
controller: SettingsSystemController,
controllerAs: 'systemVm'
},
'ui@settings.form': {
templateUrl: templateUrl('configuration/forms/ui-form/configuration-ui'),
controller: SettingsUiController,
controllerAs: 'uiVm'
},
'license@settings.form': {
templateUrl: templateUrl('license/license'),
controller: 'licenseController'
},
},
onEnter: ['$state', 'ConfigService', '$stateParams', (state, configService, stateParams) => {
return configService.getConfig()
.then(config => {
if (_.get(config, 'license_info.license_type') === 'open' && stateParams.form === 'license') {
return state.go('settings');
}
});
}],
};

View File

@ -5,13 +5,11 @@
*************************************************/
export default [
'$rootScope', '$scope', '$state', '$stateParams', '$timeout',
'AngularCodeMirror',
'$rootScope', '$scope', '$stateParams',
'systemActivityStreamForm',
'systemLoggingForm',
'systemMiscForm',
'ConfigurationService',
'ConfigurationUtils',
'SettingsUtils',
'CreateSelect2',
'GenerateForm',
'i18n',
@ -20,13 +18,11 @@ export default [
'ngToast',
'$filter',
function(
$rootScope, $scope, $state, $stateParams, $timeout,
AngularCodeMirror,
$rootScope, $scope, $stateParams,
systemActivityStreamForm,
systemLoggingForm,
systemMiscForm,
ConfigurationService,
ConfigurationUtils,
SettingsUtils,
CreateSelect2,
GenerateForm,
i18n,
@ -39,16 +35,15 @@ export default [
var generator = GenerateForm;
var formTracker = $scope.$parent.vm.formTracker;
var dropdownValue = 'misc';
var activeSystemForm = 'misc';
if ($stateParams.currentTab === 'system') {
if ($stateParams.form === 'system') {
formTracker.setCurrentSystem(activeSystemForm);
}
var activeForm = function() {
var activeForm = function(tab) {
if(!_.get($scope.$parent, [formTracker.currentFormName(), '$dirty'])) {
systemVm.activeSystemForm = systemVm.dropdownValue;
systemVm.activeSystemForm = tab;
formTracker.setCurrentSystem(systemVm.activeSystemForm);
} else {
var msg = i18n._('You have unsaved changes. Would you like to proceed <strong>without</strong> saving?');
@ -60,7 +55,7 @@ export default [
onClick: function() {
$scope.$parent.vm.populateFromApi();
$scope.$parent[formTracker.currentFormName()].$setPristine();
systemVm.activeSystemForm = systemVm.dropdownValue;
systemVm.activeSystemForm = tab;
formTracker.setCurrentSystem(systemVm.activeSystemForm);
$('#FormModal-dialog').dialog('close');
}
@ -71,7 +66,7 @@ export default [
.then(function() {
$scope.$parent[formTracker.currentFormName()].$setPristine();
$scope.$parent.vm.populateFromApi();
systemVm.activeSystemForm = systemVm.dropdownValue;
systemVm.activeSystemForm = tab;
formTracker.setCurrentSystem(systemVm.activeSystemForm);
$('#FormModal-dialog').dialog('close');
});
@ -85,16 +80,11 @@ export default [
};
var dropdownOptions = [
{label: i18n._('Misc. System'), value: 'misc'},
{label: i18n._('Activity Stream'), value: 'activity_stream'},
{label: i18n._('Logging'), value: 'logging'},
{label: i18n._('Misc. System'), value: 'misc'}
];
CreateSelect2({
element: '#system-configure-dropdown-nav',
multiple: false,
});
var systemForms = [{
formDef: systemLoggingForm,
id: 'system-logging-form'
@ -110,12 +100,12 @@ export default [
_.each(forms, function(form) {
var keys = _.keys(form.fields);
_.each(keys, function(key) {
if($scope.$parent.configDataResolve[key].type === 'choice') {
if($scope.configDataResolve[key].type === 'choice') {
// Create options for dropdowns
var optionsGroup = key + '_options';
$scope.$parent[optionsGroup] = [];
_.each($scope.$parent.configDataResolve[key].choices, function(choice){
$scope.$parent[optionsGroup].push({
$scope.$parent.$parent[optionsGroup] = [];
_.each($scope.configDataResolve[key].choices, function(choice){
$scope.$parent.$parent[optionsGroup].push({
name: choice[0],
label: choice[1],
value: choice[0]
@ -130,29 +120,29 @@ export default [
function addFieldInfo(form, key) {
_.extend(form.fields[key], {
awPopOver: ($scope.$parent.configDataResolve[key].defined_in_file) ?
null: $scope.$parent.configDataResolve[key].help_text,
label: $scope.$parent.configDataResolve[key].label,
awPopOver: ($scope.configDataResolve[key].defined_in_file) ?
null: $scope.configDataResolve[key].help_text,
label: $scope.configDataResolve[key].label,
name: key,
toggleSource: key,
dataPlacement: 'top',
placeholder: ConfigurationUtils.formatPlaceholder($scope.$parent.configDataResolve[key].placeholder, key) || null,
dataTitle: $scope.$parent.configDataResolve[key].label,
required: $scope.$parent.configDataResolve[key].required,
placeholder: SettingsUtils.formatPlaceholder($scope.configDataResolve[key].placeholder, key) || null,
dataTitle: $scope.configDataResolve[key].label,
required: $scope.configDataResolve[key].required,
ngDisabled: $rootScope.user_is_system_auditor,
disabled: $scope.$parent.configDataResolve[key].disabled || null,
readonly: $scope.$parent.configDataResolve[key].readonly || null,
definedInFile: $scope.$parent.configDataResolve[key].defined_in_file || null
disabled: $scope.configDataResolve[key].disabled || null,
readonly: $scope.configDataResolve[key].readonly || null,
definedInFile: $scope.configDataResolve[key].defined_in_file || null
});
}
$scope.$parent.parseType = 'json';
$scope.$parent.$parent.parseType = 'json';
_.each(systemForms, function(form) {
generator.inject(form.formDef, {
id: form.id,
mode: 'edit',
scope: $scope.$parent,
scope: $scope.$parent.$parent,
related: true,
noPanel: true
});
@ -173,16 +163,17 @@ export default [
});
function populateLogAggregator(flag){
if($scope.$parent.LOG_AGGREGATOR_TYPE !== null) {
$scope.$parent.LOG_AGGREGATOR_TYPE = _.find($scope.$parent.LOG_AGGREGATOR_TYPE_options, { value: $scope.$parent.LOG_AGGREGATOR_TYPE });
if($scope.$parent.$parent.LOG_AGGREGATOR_TYPE !== null) {
$scope.$parent.$parent.LOG_AGGREGATOR_TYPE = _.find($scope.$parent.$parent.LOG_AGGREGATOR_TYPE_options, { value: $scope.$parent.$parent.LOG_AGGREGATOR_TYPE });
}
if($scope.$parent.LOG_AGGREGATOR_PROTOCOL !== null) {
$scope.$parent.LOG_AGGREGATOR_PROTOCOL = _.find($scope.$parent.LOG_AGGREGATOR_PROTOCOL_options, { value: $scope.$parent.LOG_AGGREGATOR_PROTOCOL });
if($scope.$parent.$parent.LOG_AGGREGATOR_PROTOCOL !== null) {
$scope.$parent.$parent.LOG_AGGREGATOR_PROTOCOL = _.find($scope.$parent.$parent.LOG_AGGREGATOR_PROTOCOL_options, { value: $scope.$parent.$parent.LOG_AGGREGATOR_PROTOCOL });
}
if($scope.$parent.LOG_AGGREGATOR_LEVEL !== null) {
$scope.$parent.LOG_AGGREGATOR_LEVEL = _.find($scope.$parent.LOG_AGGREGATOR_LEVEL_options, { value: $scope.$parent.LOG_AGGREGATOR_LEVEL });
if($scope.$parent.$parent.LOG_AGGREGATOR_LEVEL !== null) {
$scope.$parent.$parent.LOG_AGGREGATOR_LEVEL = _.find($scope.$parent.$parent.LOG_AGGREGATOR_LEVEL_options, { value: $scope.$parent.$parent.LOG_AGGREGATOR_LEVEL });
}
if(flag !== undefined){
@ -196,18 +187,12 @@ export default [
multiple: false,
placeholder: i18n._('Select types'),
});
$scope.$parent.configuration_logging_template_form.LOG_AGGREGATOR_TYPE.$setPristine();
$scope.$parent.configuration_logging_template_form.LOG_AGGREGATOR_PROTOCOL.$setPristine();
$scope.$parent.configuration_logging_template_form.LOG_AGGREGATOR_LEVEL.$setPristine();
$scope.$parent.$parent.configuration_logging_template_form.LOG_AGGREGATOR_TYPE.$setPristine();
$scope.$parent.$parent.configuration_logging_template_form.LOG_AGGREGATOR_PROTOCOL.$setPristine();
$scope.$parent.$parent.configuration_logging_template_form.LOG_AGGREGATOR_LEVEL.$setPristine();
}
}
// Fix for bug where adding selected opts causes form to be $dirty and triggering modal
// TODO Find better solution for this bug
$timeout(function(){
$scope.$parent.configuration_logging_template_form.$setPristine();
}, 1000);
$scope.$parent.vm.testLogging = function() {
Rest.setUrl("/api/v2/settings/logging/test/");
Rest.post($scope.$parent.vm.getFormPayload())
@ -241,7 +226,6 @@ export default [
activeForm: activeForm,
activeSystemForm: activeSystemForm,
dropdownOptions: dropdownOptions,
dropdownValue: dropdownValue,
systemForms: systemForms
});
}

View File

@ -0,0 +1,49 @@
<div class="tab-pane Configuration-container">
<div class="row Form-tabRow">
<div class="col-lg-12">
<div class="Form-tabHolder">
<div ng-repeat="opt in systemVm.dropdownOptions"
class="Form-tab"
ng-click="systemVm.activeForm(opt.value)"
ng-class="{'is-selected': systemVm.activeSystemForm === opt.value }"
translate>
{{opt.label}}
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<div ng-show="systemVm.activeSystemForm === 'misc'">
<div id="system-misc-form">
</div>
</div>
<div ng-show="systemVm.activeSystemForm === 'activity_stream'">
<div id="system-activity-stream-form">
</div>
</div>
<div ng-show="systemVm.activeSystemForm === 'logging'">
<div class="form-group Form-formGroup">
<label class="Form-inputLabelContainer" for="LOG_AGGREGATOR_ENABLED">
<span class="Form-inputLabel">
Enable External Logging
</span>
<a id="awp-LOG_AGGREGATOR_ENABLED" href="" aw-pop-over="Enable sending logs to external log aggregator." data-placement="top" over-title="Enable External Logging" class="help-link" tabindex="-1">
<i class="fa fa-question-circle"></i>
</a>
</label>
<div class="ScheduleToggle" ng-class="{'is-on': LOG_AGGREGATOR_ENABLED, 'ScheduleToggle--disabled': (!LOG_AGGREGATOR_ENABLED && (!requiredLogValues.LOG_AGGREGATOR_HOST || requiredLogValues.LOG_AGGREGATOR_HOST === '' || !requiredLogValues.LOG_AGGREGATOR_TYPE || requiredLogValues.LOG_AGGREGATOR_TYPE === '')) || $rootScope.user_is_system_auditor}">
<button ng-show="LOG_AGGREGATOR_ENABLED" class="ScheduleToggle-switch is-on" ng-click="toggleForm('LOG_AGGREGATOR_ENABLED')" ng-disabled="$rootScope.user_is_system_auditor">ON</button>
<button ng-show="!LOG_AGGREGATOR_ENABLED" class="ScheduleToggle-switch" ng-click="toggleForm('LOG_AGGREGATOR_ENABLED')" ng-disabled="!requiredLogValues.LOG_AGGREGATOR_HOST || requiredLogValues.LOG_AGGREGATOR_HOST === '' || !requiredLogValues.LOG_AGGREGATOR_TYPE || requiredLogValues.LOG_AGGREGATOR_TYPE === '' || $rootScope.user_is_system_auditor">OFF</button>
</div>
</div>
<div id="system-logging-form">
</div>
</div>
</div>
</div>
</div>

View File

@ -7,37 +7,36 @@
export default [
'$scope',
'$rootScope',
'$state',
'$timeout',
'ConfigurationUiForm',
'ConfigurationService',
'CreateSelect2',
'GenerateForm',
'i18n',
'$stateParams',
function(
$scope,
$rootScope,
$state,
$timeout,
ConfigurationUiForm,
ConfigurationService,
CreateSelect2,
GenerateForm,
i18n
i18n,
$stateParams
) {
var uiVm = this;
var generator = GenerateForm;
var form = ConfigurationUiForm;
const formTracker = $scope.$parent.vm.formTracker;
if ($stateParams.form === 'ui') {
formTracker.setCurrentAuth('ui');
}
var keys = _.keys(form.fields);
_.each(keys, function(key) {
if($scope.$parent.configDataResolve[key].type === 'choice') {
if($scope.configDataResolve[key].type === 'choice') {
// Create options for dropdowns
var optionsGroup = key + '_options';
$scope.$parent[optionsGroup] = [];
_.each($scope.$parent.configDataResolve[key].choices, function(choice){
$scope.$parent[optionsGroup].push({
$scope.$parent.$parent[optionsGroup] = [];
_.each($scope.configDataResolve[key].choices, function(choice){
$scope.$parent.$parent[optionsGroup].push({
name: choice[0],
label: choice[1],
value: choice[0]
@ -52,25 +51,25 @@
function addFieldInfo(form, key) {
_.extend(form.fields[key], {
awPopOver: ($scope.$parent.configDataResolve[key].defined_in_file) ?
null: $scope.$parent.configDataResolve[key].help_text,
label: $scope.$parent.configDataResolve[key].label,
awPopOver: ($scope.configDataResolve[key].defined_in_file) ?
null: $scope.configDataResolve[key].help_text,
label: $scope.configDataResolve[key].label,
name: key,
toggleSource: key,
dataPlacement: 'top',
dataTitle: $scope.$parent.configDataResolve[key].label,
required: $scope.$parent.configDataResolve[key].required,
dataTitle: $scope.configDataResolve[key].label,
required: $scope.configDataResolve[key].required,
ngDisabled: $rootScope.user_is_system_auditor,
disabled: $scope.$parent.configDataResolve[key].disabled || null,
readonly: $scope.$parent.configDataResolve[key].readonly || null,
definedInFile: $scope.$parent.configDataResolve[key].defined_in_file || null
disabled: $scope.configDataResolve[key].disabled || null,
readonly: $scope.configDataResolve[key].readonly || null,
definedInFile: $scope.configDataResolve[key].defined_in_file || null
});
}
generator.inject(form, {
id: 'configure-ui-form',
mode: 'edit',
scope: $scope.$parent,
scope: $scope.$parent.$parent,
related: true,
noPanel: true
});
@ -79,8 +78,8 @@
var dropdownRendered = false;
function populatePendoTrackingState(flag){
if($scope.$parent.PENDO_TRACKING_STATE !== null) {
$scope.$parent.PENDO_TRACKING_STATE = _.find($scope.$parent.PENDO_TRACKING_STATE_options, { value: $scope.$parent.PENDO_TRACKING_STATE });
if($scope.$parent.$parent.PENDO_TRACKING_STATE !== null) {
$scope.$parent.$parent.PENDO_TRACKING_STATE = _.find($scope.$parent.$parent.PENDO_TRACKING_STATE_options, { value: $scope.$parent.$parent.PENDO_TRACKING_STATE });
}
if(flag !== undefined){
@ -104,10 +103,5 @@
$scope.$on('populated', function(){
populatePendoTrackingState(false);
});
angular.extend(uiVm, {
});
}
];

View File

@ -1,52 +0,0 @@
/*************************************************
* Copyright (c) 2016 Ansible, Inc.
*
* All Rights Reserved
*************************************************/
import {templateUrl} from '../shared/template-url/template-url.factory';
import { N_ } from '../i18n';
import _ from 'lodash';
export default {
name: 'configuration.license',
route: '/license',
// templateUrl: templateUrl('license/license'),
// controller: 'licenseController',
data: {},
ncyBreadcrumb: {
label: N_('LICENSE')
},
onEnter: ['$state', 'ConfigService', (state, configService) => {
return configService.getConfig()
.then(config => {
if (_.get(config, 'license_info.license_type') === 'open') {
return state.go('setup');
}
});
}],
views: {
'license@configuration': {
templateUrl: templateUrl('license/license'),
controller: 'licenseController'
},
},
resolve: {
features: ['CheckLicense', '$rootScope',
function(CheckLicense, $rootScope) {
if($rootScope.licenseMissing === undefined){
return CheckLicense.notify();
}
}],
config: ['ConfigService', 'CheckLicense', '$rootScope',
function(ConfigService, CheckLicense, $rootScope) {
ConfigService.delete();
return ConfigService.getConfig()
.then(function(config){
$rootScope.licenseMissing = (CheckLicense.valid(config.license_info) === false) ? true : false;
return config;
});
}]
},
};

View File

@ -4,40 +4,43 @@
* All Rights Reserved
*************************************************/
import configurationService from './configuration.service';
import ConfigurationUtils from './configurationUtils.service';
import configurationRoute from './configuration.route';
import licenseRoute from './license.route';
import configurationController from './configuration.controller.js';
import settingsService from './settings.service';
import settingsUtils from './settingsUtils.service';
// Import forms
//authorization sub-forms
import configurationAzureForm from './auth-form/sub-forms/auth-azure.form.js';
import configurationGithubForm from './auth-form/sub-forms/auth-github.form.js';
import configurationGithubOrgForm from './auth-form/sub-forms/auth-github-org.form';
import configurationGithubTeamForm from './auth-form/sub-forms/auth-github-team.form';
import configurationGoogleForm from './auth-form/sub-forms/auth-google-oauth2.form';
import configurationLdapForm from './auth-form/sub-forms/auth-ldap.form.js';
import configurationLdap1Form from './auth-form/sub-forms/auth-ldap1.form.js';
import configurationLdap2Form from './auth-form/sub-forms/auth-ldap2.form.js';
import configurationLdap3Form from './auth-form/sub-forms/auth-ldap3.form.js';
import configurationLdap4Form from './auth-form/sub-forms/auth-ldap4.form.js';
import configurationLdap5Form from './auth-form/sub-forms/auth-ldap5.form.js';
import configurationRadiusForm from './auth-form/sub-forms/auth-radius.form.js';
import configurationTacacsForm from './auth-form/sub-forms/auth-tacacs.form.js';
import configurationSamlForm from './auth-form/sub-forms/auth-saml.form';
import configurationAzureForm from './forms/auth-form/sub-forms/auth-azure.form.js';
import configurationGithubForm from './forms/auth-form/sub-forms/auth-github.form.js';
import configurationGithubOrgForm from './forms/auth-form/sub-forms/auth-github-org.form';
import configurationGithubTeamForm from './forms/auth-form/sub-forms/auth-github-team.form';
import configurationGoogleForm from './forms/auth-form/sub-forms/auth-google-oauth2.form';
import configurationLdapForm from './forms/auth-form/sub-forms/auth-ldap.form.js';
import configurationLdap1Form from './forms/auth-form/sub-forms/auth-ldap1.form.js';
import configurationLdap2Form from './forms/auth-form/sub-forms/auth-ldap2.form.js';
import configurationLdap3Form from './forms/auth-form/sub-forms/auth-ldap3.form.js';
import configurationLdap4Form from './forms/auth-form/sub-forms/auth-ldap4.form.js';
import configurationLdap5Form from './forms/auth-form/sub-forms/auth-ldap5.form.js';
import configurationRadiusForm from './forms/auth-form/sub-forms/auth-radius.form.js';
import configurationTacacsForm from './forms/auth-form/sub-forms/auth-tacacs.form.js';
import configurationSamlForm from './forms/auth-form/sub-forms/auth-saml.form';
//system sub-forms
import systemActivityStreamForm from './system-form/sub-forms/system-activity-stream.form.js';
import systemLoggingForm from './system-form/sub-forms/system-logging.form.js';
import systemMiscForm from './system-form/sub-forms/system-misc.form.js';
import systemActivityStreamForm from './forms/system-form/sub-forms/system-activity-stream.form.js';
import systemLoggingForm from './forms/system-form/sub-forms/system-logging.form.js';
import systemMiscForm from './forms/system-form/sub-forms/system-misc.form.js';
import configurationJobsForm from './jobs-form/configuration-jobs.form';
import configurationUiForm from './ui-form/configuration-ui.form';
import configurationJobsForm from './forms/jobs-form/configuration-jobs.form';
import configurationUiForm from './forms/ui-form/configuration-ui.form';
// Wrapper form route
import settingsFormRoute from './forms/settings-form.route';
import settingsRoute from './settings.route';
import settingsController from './settings.controller.js';
export default
angular.module('configuration', [])
.controller('ConfigurationController', configurationController)
.controller('SettingsController', settingsController)
//auth forms
.factory('configurationAzureForm', configurationAzureForm)
.factory('configurationGithubForm', configurationGithubForm)
@ -63,9 +66,9 @@ angular.module('configuration', [])
.factory('ConfigurationUiForm', configurationUiForm)
//helpers and services
.factory('ConfigurationUtils', ConfigurationUtils)
.service('ConfigurationService', configurationService)
.factory('SettingsUtils', settingsUtils)
.service('SettingsService', settingsService)
.run(['$stateExtender', function($stateExtender) {
$stateExtender.addState(configurationRoute);
$stateExtender.addState(licenseRoute);
$stateExtender.addState(settingsFormRoute);
$stateExtender.addState(settingsRoute);
}]);

View File

@ -0,0 +1,13 @@
import defaultStrings from '~assets/default.strings.json';
export default [ '$state',
function ($state) {
const vm = this;
vm.product = defaultStrings.BRAND_NAME;
vm.goToCard = (card) => {
$state.go('settings.form', { form: card });
};
}
];

View File

@ -0,0 +1,17 @@
<at-card-group>
<at-card title="Authentication" ng-click="vm.goToCard('auth')">
Enable simplified login for your Tower applications
</at-card>
<at-card title="Jobs" ng-click="vm.goToCard('jobs')">
Update settings pertaining to Jobs within Tower
</at-card>
<at-card title="System" ng-click="vm.goToCard('system')">
Define system-level features and functions
</at-card>
<at-card title="User Interface" ng-click="vm.goToCard('ui')">
Set preferences for data collection, logos, and logins
</at-card>
<at-card title="License" ng-show="vm.product === 'Tower'" ng-click="vm.goToCard('license')">
View and edit your license information
</at-card>
</at-card-group>

View File

@ -0,0 +1,40 @@
import { N_ } from '../i18n';
import {templateUrl} from '../shared/template-url/template-url.factory';
import SettingsController from './settings.controller';
// Import form controllers
export default {
name: 'settings',
route: '/settings',
ncyBreadcrumb: {
label: N_("SETTINGS")
},
resolve: {
configDataResolve: ['SettingsService', function(SettingsService){
return SettingsService.getConfigurationOptions();
}],
features: ['CheckLicense', '$rootScope',
function(CheckLicense, $rootScope) {
if($rootScope.licenseMissing === undefined){
return CheckLicense.notify();
}
}],
config: ['ConfigService', 'CheckLicense', '$rootScope',
function(ConfigService, CheckLicense, $rootScope) {
ConfigService.delete();
return ConfigService.getConfig()
.then(function(config){
$rootScope.licenseMissing = (CheckLicense.valid(config.license_info) === false) ? true : false;
return config;
});
}],
},
views: {
'': {
templateUrl: templateUrl('configuration/settings'),
controller: SettingsController,
controllerAs: 'vm'
}
}
};

View File

@ -1,49 +0,0 @@
<div class="tab-pane Configuration-container">
<div class="Form-nav--dropdownContainer">
<div class="Form-nav--dropdownLabel">Sub Category</div>
<div class="Form-nav--dropdown">
<select
id="system-configure-dropdown-nav"
class="form-control"
ng-model="systemVm.dropdownValue"
ng-options="opt.value as opt.label for opt in systemVm.dropdownOptions"
ng-change="systemVm.activeForm()">
</select>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<!-- <div id="configure-system-form"></div> -->
<div ng-show="systemVm.activeSystemForm === 'misc'">
<div id="system-misc-form">
</div>
</div>
<div ng-show="systemVm.activeSystemForm === 'activity_stream'">
<div id="system-activity-stream-form">
</div>
</div>
<div ng-show="systemVm.activeSystemForm === 'logging'">
<div class="form-group Form-formGroup">
<label class="Form-inputLabelContainer" for="LOG_AGGREGATOR_ENABLED">
<span class="Form-inputLabel" translate>
Enable External Logging
</span>
<a id="awp-LOG_AGGREGATOR_ENABLED" href="" aw-pop-over="Enable sending logs to external log aggregator." data-placement="top" over-title="Enable External Logging" class="help-link" tabindex="-1">
<i class="fa fa-question-circle"></i>
</a>
</label>
<div class="ScheduleToggle" ng-class="{'is-on': LOG_AGGREGATOR_ENABLED, 'ScheduleToggle--disabled': (!LOG_AGGREGATOR_ENABLED && (!requiredLogValues.LOG_AGGREGATOR_HOST || requiredLogValues.LOG_AGGREGATOR_HOST === '' || !requiredLogValues.LOG_AGGREGATOR_TYPE || requiredLogValues.LOG_AGGREGATOR_TYPE === '')) || $rootScope.user_is_system_auditor}">
<button ng-show="LOG_AGGREGATOR_ENABLED" class="ScheduleToggle-switch is-on" ng-click="toggleForm('LOG_AGGREGATOR_ENABLED')" ng-disabled="$rootScope.user_is_system_auditor">ON</button>
<button ng-show="!LOG_AGGREGATOR_ENABLED" class="ScheduleToggle-switch" ng-click="toggleForm('LOG_AGGREGATOR_ENABLED')" ng-disabled="!requiredLogValues.LOG_AGGREGATOR_HOST || requiredLogValues.LOG_AGGREGATOR_HOST === '' || !requiredLogValues.LOG_AGGREGATOR_TYPE || requiredLogValues.LOG_AGGREGATOR_TYPE === '' || $rootScope.user_is_system_auditor">OFF</button>
</div>
</div>
<div id="system-logging-form">
</div>
</div>
</div>
</div>
</div>
</div>

View File

@ -86,8 +86,8 @@ angular.module('AWDirectives', ['RestServices', 'Utilities'])
// Accepts image and returns base64 information with basic validation
// Can eventually expand to handle all uploads with different endpoints and handlers
//
.directive('imageUpload', ['ConfigurationUtils', 'i18n', '$rootScope',
function(ConfigurationUtils, i18n, $rootScope) {
.directive('imageUpload', ['SettingsUtils', 'i18n', '$rootScope',
function(SettingsUtils, i18n, $rootScope) {
var browseText = i18n._('BROWSE'),
placeholderText = i18n._('Choose file'),
uploadedText = i18n._('Current Image: '),
@ -157,7 +157,7 @@ function(ConfigurationUtils, i18n, $rootScope) {
scope.fileChange = function(file) {
filePickerError.html('');
ConfigurationUtils.imageProcess(file[0])
SettingsUtils.imageProcess(file[0])
.then(function(result) {
scope.$parent[fieldKey] = result;
filePickerText.val(file[0].name);

View File

@ -48,7 +48,6 @@ export default
scrollbarStyle: null
}
};
scope[fld + 'codeMirror'] = AngularCodeMirror(readOnly);
scope[fld + 'codeMirror'].addModes(variableEditModes);
scope[fld + 'codeMirror'].showTextArea({
@ -61,7 +60,6 @@ export default
onChange: onChange
});
}
// Hide the textarea and show a CodeMirror editor
createField(onChange, onReady, fld);

View File

@ -14,6 +14,17 @@ const commands = [{
return this.navigate();
},
selectSubcategory (name) {
const spinny = 'div.spinny';
const categoryName = `//*[text() = '${name}']`;
this.api.useXpath();
this.api.waitForElementVisible(categoryName);
this.api.click(categoryName);
this.api.useCss();
return this;
},
selectDropDownContainer (name) {
const spinny = 'div.spinny';
const select = '#configure-dropdown-nav';
const arrow = `${select} + span span[class$="arrow"]`;

View File

@ -18,7 +18,10 @@ const navigation = {
notifications: 'i[class$="fa-bell"]',
managementJobs: 'i[class$="fa-wrench"]',
instanceGroups: 'i[class$="fa-server"]',
settings: 'i[class$="fa-cog"]',
settings: 'i[class*="fa-cog"]',
settingsSubPane: '.at-SettingsSubPane',
settingsSubPaneSystem: 'a[href="#/settings/system"]',
settingsSubPaneAuth: 'a[href="#/settings/auth"]'
}
};

View File

@ -1,9 +1,7 @@
module.exports = {
'expected LDAP codemirror fields are rendered when returning from another tab': client => {
const authTab = '#auth_tab';
const authView = 'div[ui-view="auth"]';
const ldapForm = '#configuration_ldap_template_form';
const systemTab = '#system_tab';
const systemView = 'div[ui-view="system"]';
const { navigation } = client.page.dashboard().section;
@ -14,20 +12,23 @@ module.exports = {
navigation
.waitForElementVisible('@settings')
.click('@settings');
.moveToElement('@settings', 0, 0)
.waitForElementVisible('@settingsSubPaneSystem')
.click('@settingsSubPaneSystem');
configuration.waitForElementVisible(authView);
configuration.waitForElementVisible(systemTab);
configuration.click(systemTab);
configuration.waitForElementNotVisible(authView);
configuration.waitForElementVisible(systemView);
configuration.waitForElementVisible(authTab);
configuration.click(authTab);
configuration.waitForElementNotVisible(systemView);
navigation
.waitForElementVisible('@settings')
.moveToElement('@settings', 0, 0)
.waitForElementVisible('@settingsSubPane')
.waitForElementVisible('@settingsSubPaneAuth')
.click('@settingsSubPaneAuth');
configuration.waitForElementVisible(authView);
// works as xpath const categoryName =
// `//*[@id="configuration_edit"]/div[1]/div/div/div[4]`;
configuration.selectSubcategory('LDAP');
configuration.waitForElementVisible(ldapForm);
@ -41,7 +42,7 @@ module.exports = {
'AUTH_LDAP_TEAM_MAP',
];
const ldapCodeMirrors = `${ldapForm} div[class^="CodeMirror"] textarea`;
const ldapCodeMirrors = `${ldapForm} div[class^="CodeMirror"] textarea`;
client.elements('css selector', ldapCodeMirrors, ({ value }) => {
client.assert.equal(value.length, expectedCodemirrorFields.length);