diff --git a/awx/ui/client/src/configuration/configuration.block.less b/awx/ui/client/src/configuration/configuration.block.less index 9c6c855274..edf80e01a8 100644 --- a/awx/ui/client/src/configuration/configuration.block.less +++ b/awx/ui/client/src/configuration/configuration.block.less @@ -1,11 +1,16 @@ -.Form-resetValue { - float: right; +@import "./client/src/shared/branding/colors.default.less"; + +.Form-resetValue, .Form-resetFile { text-transform: uppercase; font-weight: normal; cursor: pointer; font-size: 12px; } +.Form-resetValue { + float: right +} + .Form-tab { min-width: 77px; } @@ -25,3 +30,22 @@ .Form-tabRow { width: 80%; } + +input.Form-filePicker { + width: 0.1px; + height: 0.1px; + opacity: 0; + overflow: hidden; + position: absolute; + z-index: -1; +} +label#filePickerButton { + cursor: pointer; + background-color: #fff; + color: @default-interface-txt; +} +input#filePickerText { + cursor: default; + border-radius: 0 5px 5px 0; + background-color: #fff; +} diff --git a/awx/ui/client/src/configuration/configuration.controller.js b/awx/ui/client/src/configuration/configuration.controller.js index 5ec6c0abca..d1e4995ca6 100644 --- a/awx/ui/client/src/configuration/configuration.controller.js +++ b/awx/ui/client/src/configuration/configuration.controller.js @@ -5,8 +5,8 @@ *************************************************/ export default [ - '$scope', '$state', '$stateParams', '$timeout', '$q', 'Alert', 'ClearScope', - 'ConfigurationService', 'ConfigurationUtils', 'CreateDialog', 'CreateSelect2', 'ParseTypeChange', 'ProcessErrors', + '$scope', '$rootScope', '$state', '$stateParams', '$timeout', '$q', 'Alert', 'ClearScope', + 'ConfigurationService', 'ConfigurationUtils', 'CreateDialog', 'CreateSelect2', 'ParseTypeChange', 'ProcessErrors', 'Store', 'Wait', 'configDataResolve', //Form definitions 'configurationGithubForm', @@ -20,8 +20,8 @@ export default [ 'ConfigurationSystemForm', 'ConfigurationUiForm', function( - $scope, $state, $stateParams, $timeout, $q, Alert, ClearScope, - ConfigurationService, ConfigurationUtils, CreateDialog, CreateSelect2, ParseTypeChange, ProcessErrors, + $scope, $rootScope, $state, $stateParams, $timeout, $q, Alert, ClearScope, + ConfigurationService, ConfigurationUtils, CreateDialog, CreateSelect2, ParseTypeChange, ProcessErrors, Store, Wait, configDataResolve, //Form definitions configurationGithubForm, @@ -238,6 +238,7 @@ export default [ ConfigurationService.patchConfiguration(payload) .then(function() { $scope[key] = $scope.configDataResolve[key].default; + loginUpdate(); }) .catch(function(error) { ProcessErrors($scope, error, status, formDefs[formTracker.getCurrent()], @@ -271,6 +272,21 @@ export default [ } } + function loginUpdate() { + // Updates the logo and app config so that logos are properly shown + // on logout after modifying. + if($scope.CUSTOM_LOGO) { + $rootScope.custom_logo = $scope.$parent.CUSTOM_LOGO; + global.$AnsibleConfig.custom_logo = true; + Store('AnsibleConfig', global.$AnsibleConfig); + } else { + $rootScope.custom_logo = ''; + global.$AnsibleConfig.custom_logo = false; + Store('AnsibleConfig', global.$AnsibleConfig); + } + $scope.$broadcast('loginUpdated'); + } + // Some dropdowns are listed as "list" type in the API even though they're a dropdown: var multiselectDropdowns = ['AD_HOC_COMMANDS']; var formSave = function() { @@ -313,6 +329,7 @@ export default [ Wait('start'); ConfigurationService.patchConfiguration(payload) .then(function(data) { + loginUpdate(); saveDeferred.resolve(data); $scope[formTracker.currentFormName()].$setPristine(); }) @@ -331,6 +348,8 @@ export default [ return saveDeferred.promise; }; + + $scope.toggleForm = function(key) { $scope[key] = !$scope[key]; Wait('start'); diff --git a/awx/ui/client/src/configuration/configurationUtils.service.js b/awx/ui/client/src/configuration/configurationUtils.service.js index b8758c308e..7620d6917d 100644 --- a/awx/ui/client/src/configuration/configurationUtils.service.js +++ b/awx/ui/client/src/configuration/configurationUtils.service.js @@ -4,8 +4,8 @@ * All Rights Reserved *************************************************/ -export default [ - function() { +export default ['$q', + function($q) { return { listToArray: function(input) { @@ -64,6 +64,33 @@ export default [ } else { return input; } + }, + + imageProcess: function(file) { + var deferred = $q.defer(); + var SIZELIMIT = 1000000; // 1 MB + var ACCEPTEDFORMATS = ['image/png', 'image/gif', 'image/jpeg']; //Basic check + + if(file.size < SIZELIMIT && ACCEPTEDFORMATS.indexOf(file.type) !== -1) { + var reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = function () { + deferred.resolve(reader.result); + }; + reader.onerror = function () { + deferred.reject('File could not be parsed'); + }; + } else { + var error = 'Error: '; + if(file.size > SIZELIMIT) { + error += 'Must be under ' + SIZELIMIT / 1000000 + 'MB. '; + } + if(ACCEPTEDFORMATS.indexOf(file.type) === -1) { + error += 'Wrong file type - must be png, gif, or jpg.'; + } + deferred.reject(error); + } + return deferred.promise; } }; diff --git a/awx/ui/client/src/configuration/ui-form/configuration-ui.form.js b/awx/ui/client/src/configuration/ui-form/configuration-ui.form.js index c3a849c5a4..0cd79fad9c 100644 --- a/awx/ui/client/src/configuration/ui-form/configuration-ui.form.js +++ b/awx/ui/client/src/configuration/ui-form/configuration-ui.form.js @@ -4,33 +4,39 @@ * All Rights Reserved *************************************************/ - export default function() { - return { - showHeader: false, - name: 'configuration_ui_template', - showActions: true, +export default function() { + return { + showHeader: false, + name: 'configuration_ui_template', + showActions: true, - fields: { - PENDO_TRACKING_STATE: { - type: 'select', - ngChange: 'changedPendo()', - ngOptions: 'choice.label for choice in PENDO_TRACKING_STATE_options track by choice.value', - reset: 'PENDO_TRACKING_STATE' - } - }, - buttons: { - reset: { - ngClick: 'vm.resetAllConfirm()', - label: 'Reset All', - class: 'Form-button--left Form-cancelButton' - }, - cancel: { - ngClick: 'vm.formCancel()', - }, - save: { - ngClick: 'vm.formSave()', - ngDisabled: true - } - } - }; - } + fields: { + PENDO_TRACKING_STATE: { + type: 'select', + ngChange: 'changedPendo()', + ngOptions: 'choice.label for choice in PENDO_TRACKING_STATE_options track by choice.value', + reset: 'PENDO_TRACKING_STATE' + }, + CUSTOM_LOGO: { + type: 'custom', + reset: 'CUSTOM_LOGO', + control: `` + }, + }, + + buttons: { + reset: { + ngClick: 'vm.resetAllConfirm()', + label: 'Reset All', + class: 'Form-button--left Form-cancelButton' + }, + cancel: { + ngClick: 'vm.formCancel()', + }, + save: { + ngClick: 'vm.formSave()', + ngDisabled: true + } + } + }; +} diff --git a/awx/ui/client/src/configuration/ui-form/configuration-ui.partial.html b/awx/ui/client/src/configuration/ui-form/configuration-ui.partial.html index d880be7025..82ab146e93 100644 --- a/awx/ui/client/src/configuration/ui-form/configuration-ui.partial.html +++ b/awx/ui/client/src/configuration/ui-form/configuration-ui.partial.html @@ -1,6 +1,4 @@
-
diff --git a/awx/ui/client/src/helpers/LoadConfig.js b/awx/ui/client/src/helpers/LoadConfig.js index eeab13bb50..c3ba75e4c7 100644 --- a/awx/ui/client/src/helpers/LoadConfig.js +++ b/awx/ui/client/src/helpers/LoadConfig.js @@ -22,14 +22,14 @@ export default angular.module('LoadConfigHelper', ['Utilities']) -.factory('LoadConfig', ['$log', '$rootScope', '$http', '$location', - 'ProcessErrors', 'Store', - function($log, $rootScope, $http, $location, ProcessErrors, Store) { +.factory('LoadConfig', ['$log', '$rootScope', '$http', '$location', 'GetBasePath', + 'ProcessErrors', 'Rest', 'Store', + function($log, $rootScope, $http, $location, GetBasePath, ProcessErrors, Rest, Store) { return function() { // These ettings used to be found in config.js, hardcoded now. var configSettings = { - // custom_logo: true, // load /var/lib/awx/public/static/assets/custom_console_logo.png as the login modal header. if false, will load the standard tower console logo + //custom_logo: false, // load /var/lib/awx/public/static/assets/custom_console_logo.png as the login modal header. if false, will load the standard tower console logo // custom_login_info: "example notice", // have a notice displayed in the login modal for users. note that, as a security measure, custom html is not supported and will be escaped. "tooltip_delay": { "show": 500, @@ -62,22 +62,37 @@ angular.module('LoadConfigHelper', ['Utilities']) }, }; - // Auto-resolving what used to be found when attempting to load local_setting.json - if ($rootScope.loginConfig) { - $rootScope.loginConfig.resolve('config loaded'); - } - $rootScope.$emit('ConfigReady'); + var configInit = function() { + // Auto-resolving what used to be found when attempting to load local_setting.json + if ($rootScope.loginConfig) { + $rootScope.loginConfig.resolve('config loaded'); + } + $rootScope.$emit('ConfigReady'); - // Load new hardcoded settings from above - // TODO Add a check for a custom image to add to the settings. - // Update flag to true - // in loginModal.controller load the base64 src - // change partial to use base65 in the img src + // Load new hardcoded settings from above - global.$AnsibleConfig = configSettings; - Store('AnsibleConfig', global.$AnsibleConfig); - $rootScope.$emit('LoadConfig'); + global.$AnsibleConfig = configSettings; + Store('AnsibleConfig', global.$AnsibleConfig); + $rootScope.$emit('LoadConfig'); + }; + // Retrieve the custom logo information - update configSettings from above + $http({ + method: 'GET', + url: '/api', + }) + .success(function(response) { + if(response.custom_logo) { + configSettings.custom_logo = true; + $rootScope.custom_logo = response.custom_logo; + configInit(); + } else { + configSettings.custom_logo = false; + configInit(); + } + }).error(function(error) { + console.log(error); + }); }; } diff --git a/awx/ui/client/src/login/loginModal/loginModal.controller.js b/awx/ui/client/src/login/loginModal/loginModal.controller.js index 69d509925f..635ced3e20 100644 --- a/awx/ui/client/src/login/loginModal/loginModal.controller.js +++ b/awx/ui/client/src/login/loginModal/loginModal.controller.js @@ -93,7 +93,7 @@ export default ['$log', '$cookieStore', '$compile', '$window', '$rootScope', $rootScope.loginConfig.promise.then(function () { if ($AnsibleConfig.custom_logo) { - scope.customLogo = "custom_console_logo.png"; + scope.customLogo = $rootScope.custom_logo; scope.customLogoPresent = true; } else { scope.customLogo = "tower-logo-login.svg"; diff --git a/awx/ui/client/src/login/loginModal/loginModal.partial.html b/awx/ui/client/src/login/loginModal/loginModal.partial.html index e0e46657f8..d6e30a20a3 100644 --- a/awx/ui/client/src/login/loginModal/loginModal.partial.html +++ b/awx/ui/client/src/login/loginModal/loginModal.partial.html @@ -6,8 +6,12 @@ ng-class="{'is-loggedOut' : !current_user || !current_user.username}">
+
diff --git a/awx/ui/client/src/shared/directives.js b/awx/ui/client/src/shared/directives.js index 433bbbcb78..16a0faea9a 100644 --- a/awx/ui/client/src/shared/directives.js +++ b/awx/ui/client/src/shared/directives.js @@ -123,6 +123,77 @@ angular.module('AWDirectives', ['RestServices', 'Utilities', 'JobsHelper']) }; }]) +// imageUpload +// +// Accepts image and returns base64 information with basic validation +// Can eventually expand to handle all uploads with different endpoints and handlers +// +.directive('imageUpload', ['ConfigurationUtils', function(ConfigurationUtils) { + return { + restrict: 'E', + scope: { + key: '@' + }, + template: ` +
+ + + +
+ + +
`, + + link: function(scope) { + var fieldKey = scope.key; + var filePickerText = angular.element(document.getElementById('filePickerText')); + var filePickerError = angular.element(document.getElementById('filePickerError')); + var filePickerButton = angular.element(document.getElementById('filePickerButton')); + + scope.imagePresent = global.$AnsibleConfig.custom_logo; + + scope.$on('loginUpdated', function() { + scope.imagePresent = global.$AnsibleConfig.custom_logo; + }); + + scope.update = function(e) { + if(scope.$parent[fieldKey]) { + e.preventDefault(); + scope.$parent[fieldKey] = ''; + filePickerButton.html('BROWSE'); + filePickerText.val(''); + } + else { + // Nothing exists so open file picker + } + }; + + scope.fileChange = function(file) { + filePickerError.html(''); + + ConfigurationUtils.imageProcess(file[0]) + .then(function(result) { + scope.$parent[fieldKey] = result; + filePickerText.val(file[0].name); + filePickerButton.html('REMOVE'); + }).catch(function(error) { + filePickerText.html(file[0].name); + filePickerError.text(error); + }).finally(function() { + + }); + }; + + } + }; +}]) + .directive('surveyCheckboxes', function() { return {