mirror of
https://github.com/ansible/awx.git
synced 2024-11-01 08:21:15 +03:00
Added image upload for custom logo
This commit is contained in:
parent
99fd30e84f
commit
8028b7ef75
@ -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;
|
||||
}
|
||||
|
@ -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');
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
};
|
||||
|
@ -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: `<image-upload key="CUSTOM_LOGO"></image-upload>`
|
||||
},
|
||||
},
|
||||
|
||||
buttons: {
|
||||
reset: {
|
||||
ngClick: 'vm.resetAllConfirm()',
|
||||
label: 'Reset All',
|
||||
class: 'Form-button--left Form-cancelButton'
|
||||
},
|
||||
cancel: {
|
||||
ngClick: 'vm.formCancel()',
|
||||
},
|
||||
save: {
|
||||
ngClick: 'vm.formSave()',
|
||||
ngDisabled: true
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -1,6 +1,4 @@
|
||||
<div class="tab-pane Configuration-container">
|
||||
<!-- <div ui-view="form"></div>
|
||||
<div ng-cloak id="htmlTemplate"> -->
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div id="configure-ui-form"></div>
|
||||
|
@ -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);
|
||||
});
|
||||
|
||||
};
|
||||
}
|
||||
|
@ -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";
|
||||
|
@ -6,8 +6,12 @@
|
||||
ng-class="{'is-loggedOut' : !current_user || !current_user.username}">
|
||||
<div class="LoginModal-header">
|
||||
<img id="login_modal_image" class="LoginModal-logoImage"
|
||||
ng-if="!customLogoPresent"
|
||||
ng-class="{'LoginModal-logoImage--notCustom': !customLogoPresent}"
|
||||
ng-src="/static/assets/{{ customLogo }}" >
|
||||
<img id="login_modal_image" class="LoginModal-logoImage"
|
||||
ng-if="customLogoPresent"
|
||||
ng-src="{{ customLogo }}" >
|
||||
</div>
|
||||
<div class="LoginModal-body">
|
||||
<div class="LoginModal-alert" ng-show="!sessionExpired && !sessionLimitExpired && !attemptFailed && !thirdPartyAttemptFailed" translate>
|
||||
|
@ -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: `
|
||||
<div class="input-group">
|
||||
<label class="input-group-addon Form-filePicker--pickerButton" id="filePickerButton" for="filePicker" ng-click="update($event)">BROWSE</label>
|
||||
<input type="text" class="form-control Form-filePicker--textBox" id="filePickerText" placeholder="Choose file" readonly>
|
||||
<input type="file" name="file" class="Form-filePicker" id="filePicker" onchange="angular.element(this).scope().fileChange(this.files)"/>
|
||||
</div>
|
||||
<!-- Update when API supports file name saving
|
||||
<div ng-if="imagePresent" class="Form-filePicker--selectedFile">
|
||||
Custom logo has been uploaded.
|
||||
</div>-->
|
||||
<!-- Thumbnail feature
|
||||
<div class="thumbnail">
|
||||
<img src="{{image}}" alt="Current logo">
|
||||
</div> -->
|
||||
<div class="error" id="filePickerError"></div>`,
|
||||
|
||||
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 {
|
||||
|
Loading…
Reference in New Issue
Block a user