| # | +Name | ++ |
|---|---|---|
| {{$index + 1}} | +{{car}} | ++ + + | +
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..a2444ef
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,45 @@
+FROM ubuntu:xenial
+
+MAINTAINER John Walsh Advanced Templates Tracks Cars
| # | +Name | ++ |
|---|---|---|
| {{$index + 1}} | +{{car}} | ++ + + | +
- + - - + + + - + diff --git a/frontend/app/angular-toggle-switch.js b/frontend/app/angular-toggle-switch.js index 41ee4de..b28dce1 100644 --- a/frontend/app/angular-toggle-switch.js +++ b/frontend/app/angular-toggle-switch.js @@ -12,13 +12,13 @@ angular.module('toggle-switch', ['ng']).directive('toggleSwitch', ['$compile', f onChange: '&' }, template: - '
', + '
', compile: function(element, attrs) { if (angular.isUndefined(attrs.onLabel)) { attrs.onLabel = 'Yes'; diff --git a/frontend/app/app.js b/frontend/app/app.js index 12b6e39..be9b60f 100644 --- a/frontend/app/app.js +++ b/frontend/app/app.js @@ -1,18 +1,19 @@ 'use strict'; angular - .module('acServerManager', ['acServerManager.services', 'ui.bootstrap', 'ui.bootstrap.showErrors', 'toggle-switch']) - -.directive('stringToNumber', function() { - return { - require: 'ngModel', - link: function(scope, element, attrs, ngModel) { - ngModel.$parsers.push(function(value) { - return '' + value; - }); - ngModel.$formatters.push(function(value) { - return parseFloat(value, 10); - }); - } - }; -}); \ No newline at end of file + .module('acServerManager', ['acServerManager.services', 'ui.bootstrap', 'ui.bootstrap.showErrors', 'toggle-switch']) + // Use lodash in controllers + .constant('_', window._) + .directive('stringToNumber', function() { + return { + require: 'ngModel', + link: function(scope, element, attrs, ngModel) { + ngModel.$parsers.push(function(value) { + return '' + value; + }); + ngModel.$formatters.push(function(value) { + return parseFloat(value, 10); + }); + } + }; + }); diff --git a/frontend/app/controllers.js b/frontend/app/controllers.js index 246e83d..a2c81f7 100644 --- a/frontend/app/controllers.js +++ b/frontend/app/controllers.js @@ -1,7 +1,7 @@ 'use strict'; angular.module('acServerManager') - .controller('StatusCtrl', function($scope, $timeout, ProcessService, ServerService) { + .controller('StatusCtrl', function($scope, $timeout, ProcessService, ServerService) { $scope.alerts = []; (function getACServerStatus() { @@ -28,7 +28,7 @@ angular.module('acServerManager') $scope.startACServer = function() { ProcessService.StartACServer(function(result) { if (!(result[0] === 'O' && result[1] === 'K')) { - createAlert('warning', 'Failed to start AC server', true) + createAlert('warning', 'Failed to start AC server', 'pe-7s-server'); } }) } @@ -37,7 +37,7 @@ angular.module('acServerManager') $scope.stopSTrackerServer(); ProcessService.StopACServer(function(result) { if (!(result[0] === 'O' && result[1] === 'K')) { - createAlert('warning', 'Failed to stop AC server', true) + createAlert('warning', 'Failed to stop AC server', 'pe-7s-server'); } }) } @@ -45,7 +45,7 @@ angular.module('acServerManager') $scope.restartACServer = function() { ProcessService.RestartACServer(function(result) { if (!(result[0] === 'O' && result[1] === 'K')) { - createAlert('warning', 'Failed to restart AC server', true) + createAlert('warning', 'Failed to restart AC server', 'pe-7s-server'); } }) } @@ -53,7 +53,7 @@ angular.module('acServerManager') $scope.startSTrackerServer = function() { ProcessService.StartSTrackerServer(function(result) { if (!(result[0] === 'O' && result[1] === 'K')) { - createAlert('warning', 'Failed to start stracker', true) + createAlert('warning', 'Failed to start stracker', 'pe-7s-server'); } }) } @@ -61,7 +61,7 @@ angular.module('acServerManager') $scope.stopSTrackerServer = function() { ProcessService.StopSTrackerServer(function(result) { if (!(result[0] === 'O' && result[1] === 'K')) { - createAlert('warning', 'Failed to stop stracker', true) + createAlert('warning', 'Failed to stop stracker', 'pe-7s-server'); } }) } @@ -69,7 +69,7 @@ angular.module('acServerManager') $scope.restartSTrackerServer = function() { ProcessService.RestartSTrackerServer(function(result) { if (!(result[0] === 'O' && result[1] === 'K')) { - createAlert('warning', 'Failed to restart stracker', true) + createAlert('warning', 'Failed to restart stracker', 'pe-7s-server'); } }) } @@ -78,16 +78,102 @@ angular.module('acServerManager') $scope.alerts.splice(index, 1); }; - function createAlert(type, msg, autoClose) { - var alert = { type: type, msg: msg}; - $scope.alerts.push(alert); - if (autoClose) { - $timeout(function(){ - $scope.alerts.splice($scope.alerts.indexOf(alert), 1); - }, 3000); - } + function createAlert(type, msg, icon) { + $.notify({ + icon: icon, + message: msg + },{ + type: type, + timer: 3000 + }); } }) + .controller('TemplatesCtrl', function ($scope, $filter, $timeout, TemplateService) { + $scope.templateList = []; + + TemplateService.GetTemplates(function (data) { + $scope.templateList = data; + }); + + $scope.loadTemplate = function(index) { + if (!confirm('Are you sure?')) { + return; + } + try { + var loaded = true; + var template = $scope.templateList[index]; + TemplateService.LoadTemplate(template, function(result) { + if (!(result[0] === 'O' && result[1] === 'K')) { + loaded = false; + } + }); + if (loaded) { + createAlert('success', 'Loaded succesfully, remember to restart server!', 'pe-7s-star'); + } else { + createAlert('warning', 'Load failed!', 'pe-7s-close-circle'); + } + } catch (e) { + console.log('Error - ' + e); + } + } + + $scope.removeTemplate = function(index) { + if (!confirm('Are you sure?')) { + return; + } + try { + var template = $scope.templateList[index]; + TemplateService.RemoveTemplate(template, function(result) { + if (!(result[0] === 'O' && result[1] === 'K')) { + createAlert('warning', 'Remove failed', 'pe-7s-close-circle'); + } else { + $scope.templateList.splice(index, 1) + createAlert('success', 'Removed succesfully', 'pe-7s-star'); + } + }); + } catch (e) { + console.log('Error - ' + e); + } + } + + $scope.saveCurrent = function() { + $scope.$broadcast('show-errors-check-validity'); + + if ($scope.form.$invalid) { + createAlert('warning', 'There are errors on the form', 'pe-7s-note'); + return; + } + + try { + var saved = true; + var template = angular.copy($scope.newTemplate); + TemplateService.SaveCurrent(template, function(result) { + if (!(result[0] === 'O' && result[1] === 'K')) { + saved = false; + } else { + $scope.templateList.push(template); + } + }); + if (saved) { + createAlert('success', 'Saved succesfully', 'pe-7s-star'); + } else { + createAlert('warning', 'Save failed', 'pe-7s-close-circle'); + } + } catch (e) { + console.log('Error - ' + e); + } + } + + function createAlert(type, msg, icon) { + $.notify({ + icon: icon, + message: msg + },{ + type: type, + timer: 3000 + }); + } + }) .controller('ServerCtrl', function ($scope, $filter, $timeout, CarService, TrackService, ServerService, BookService, PracticeService, QualifyService, RaceService, TyreService, WeatherService) { $scope.sessions = []; $scope.alerts = []; @@ -188,23 +274,21 @@ angular.module('acServerManager') }); ServerService.GetServerDetails(function (data) { - $scope.server = data; - try { - $scope.selectedCars = data.CARS.split(';'); - $scope.selectedTracks = data.TRACK; //TODO: Multi-track - $scope.selectedTyres = data.LEGAL_TYRES.split(';'); - data.LOOP_MODE = data.LOOP_MODE == 1; data.LOCKED_ENTRY_LIST = data.LOCKED_ENTRY_LIST == 1; data.PICKUP_MODE_ENABLED = data.PICKUP_MODE_ENABLED == 1; data.REGISTER_TO_LOBBY = data.REGISTER_TO_LOBBY == 1; - - if(data.SUN_ANGLE > 0){ - var time = getTime(data.SUN_ANGLE); - $scope.hours = time.getHours(); - $scope.mins = time.getMinutes(); - } + + $scope.server = data; + + $scope.selectedCars = data.CARS.split(';'); + $scope.selectedTracks = data.TRACK; + $scope.selectedTyres = data.LEGAL_TYRES.split(';'); + + var time = getTime(data.SUN_ANGLE); + $scope.hours = time.getHours(); + $scope.mins = time.getMinutes(); } catch (e) { console.log('Error - ' + e); } @@ -304,7 +388,9 @@ angular.module('acServerManager') if (track !== null) { if (track.configs && track.configs.length) { $scope.configs = track.configs; - $scope.server.CONFIG_TRACK = $scope.configs[0]; + var index = $scope.configs.indexOf($scope.server.CONFIG_TRACK); + var index = (index !== -1) ? index : 0; + $scope.server.CONFIG_TRACK = $scope.configs[index]; TrackService.GetTrackDetails(track.name, $scope.server.CONFIG_TRACK, function(data) { $scope.trackDetails = data; @@ -328,7 +414,7 @@ angular.module('acServerManager') $scope.$broadcast('show-errors-check-validity'); if ($scope.form.$invalid) { - createAlert('warning', 'There are errors on the form', true); + createAlert('warning', 'There are errors on the form', 'pe-7s-note'); return; } @@ -340,8 +426,11 @@ angular.module('acServerManager') data.PICKUP_MODE_ENABLED = $scope.server.PICKUP_MODE_ENABLED ? 1 : 0; data.REGISTER_TO_LOBBY = $scope.server.REGISTER_TO_LOBBY ? 1 : 0; data.CARS = $scope.selectedCars.join(';'); - data.TRACK = $scope.selectedTracks; //TODO: Multi-track - data.SUN_ANGLE = getSunAngle($scope.hours, $scope.mins); + data.TRACK = $scope.selectedTracks; + + if($scope.hours || $scope.mins){ + data.SUN_ANGLE = getSunAngle($scope.hours, $scope.mins); + } if (typeof $scope.tyres.length === 'undefined' || !$scope.tyres.length){ data.LEGAL_TYRES = $scope.selectedTyres.length === $scope.tyres.length ? '' : $scope.selectedTyres.join(';'); @@ -418,9 +507,9 @@ angular.module('acServerManager') }); if (saved) { - createAlert('success', 'Saved successfully', true); - } else { - createAlert('warning', 'Save failed', true); + createAlert('success', 'Saved successfully', 'pe-7s-star'); + } else { + createAlert('warning', 'Save failed', 'pe-7s-close-circle'); } } catch (e) { console.log('Error - ' + e); @@ -430,7 +519,7 @@ angular.module('acServerManager') $scope.closeAlert = function(index) { $scope.alerts.splice(index, 1); }; - + function getTime(sunAngle) { var baseLine = new Date(2000, 1, 1, 13, 0, 0, 0); var offset = sunAngle / 16; @@ -438,7 +527,7 @@ angular.module('acServerManager') baseLine.setMinutes(baseLine.getMinutes() + multiplier); return baseLine; } - + function getSunAngle(hours, mins) { var baseLine = new Date(2000, 1, 1, 13, 0, 0, 0); var time = new Date(2000, 1, 1, hours, mins, 0); @@ -448,15 +537,15 @@ angular.module('acServerManager') var sunAngle = multiplier * 16; return sunAngle; } - - function createAlert(type, msg, autoClose) { - var alert = { type: type, msg: msg}; - $scope.alerts.push(alert); - if (autoClose) { - $timeout(function(){ - $scope.alerts.splice($scope.alerts.indexOf(alert), 1); - }, 3000); - } + + function createAlert(type, msg, icon) { + $.notify({ + icon: icon, + message: msg + },{ + type: type, + timer: 3000 + }); } function findInArray(arr, search) { @@ -481,7 +570,8 @@ angular.module('acServerManager') SKIN: '', GUID: '', SPECTATOR_MODE: '', - BALLAST: 0 + BALLAST: 0, + RESTRICTOR: 0 }; $scope.$watchCollection('newEntry', function (newVal, oldVal) { @@ -529,7 +619,7 @@ angular.module('acServerManager') $scope.$broadcast('show-errors-check-validity'); if ($scope.form.$invalid) { - createAlert('warning', 'There are errors on the form', true); + createAlert('warning', 'There are errors on the form', 'pe-7s-note'); return; } @@ -548,7 +638,8 @@ angular.module('acServerManager') SKIN: '', GUID: '', SPECTATOR_MODE: '', - BALLAST: 0 + BALLAST: 0, + RESTRICTOR: 0 }; $scope.selectedCarChanged(); } @@ -562,9 +653,9 @@ angular.module('acServerManager') EntryListService.SaveEntryList(data, function(result) { if (result[0] === 'O' && result[1] === 'K') { - createAlert('success', 'Saved successfully', true); - } else { - createAlert('warning', 'Save failed', true); + createAlert('success', 'Saved successfully', 'pe-7s-star'); + } else { + createAlert('warning', 'Save failed', 'pe-7s-close-circle'); } }); } @@ -579,7 +670,7 @@ angular.module('acServerManager') $scope.$broadcast('show-errors-check-validity'); if ($scope.createForm.$invalid) { - createAlert('warning', 'There are errors on the form', true); + createAlert('warning', 'There are errors on the form', 'pe-7s-note'); return; } @@ -588,7 +679,7 @@ angular.module('acServerManager') $scope.drivers.push($scope.newDriver); $scope.newDriver = {}; } else { - createAlert('warning', 'Save failed', true); + createAlert('warning', 'Save failed', 'pe-7s-close-circle'); } }); } @@ -605,7 +696,7 @@ angular.module('acServerManager') }); } } else { - createAlert('warning', 'Delete failed', true); + createAlert('warning', 'Delete failed', 'pe-7s-close-circle'); } }); } @@ -616,16 +707,361 @@ angular.module('acServerManager') $scope.newEntry.GUID = driver.GUID; } - function createAlert(type, msg, autoClose) { - var alert = { type: type, msg: msg}; - $scope.alerts.push(alert); - if (autoClose) { - $timeout(function(){ - $scope.alerts.splice($scope.alerts.indexOf(alert), 1); - }, 3000); - } + function createAlert(type, msg, icon) { + $.notify({ + icon: icon, + message: msg + },{ + type: type, + timer: 3000 + }); } }) + .controller('CarCtrl', function($scope, Upload, $timeout, $q, CarService) { + $scope.alerts = []; + $scope.files = []; + $scope.userDropped = false; + $scope.newCar = { + name: '', + data: [], + mod_tyres: '', + skins: [], + $valid: false + }; + + CarService.GetCars(function (data) { + $scope.cars = data; + }); + + $scope.$watch('files', function() { + $scope.validateCar($scope.files); + }); + + $scope.removeCar = function(index) { + if (!confirm('Are you sure?')) { + return; + } + try { + var car = $scope.cars[index]; + CarService.RemoveCar(car, function(result) { + if (!(result[0] === 'O' && result[1] === 'K')) { + createAlert('warning', 'Remove failed', 'pe-7s-close-circle'); + } else { + $scope.cars.splice(index, 1); + createAlert('success', 'Removed succesfully', 'pe-7s-star'); + } + }); + } catch(e) { + console.log('Error - ' + e); + } + } + + $scope.resetNewCar = function() { + $scope.newCar.$valid = false; + $scope.newCar.name = ''; + $scope.newCar.data = []; + $scope.newCar.mod_tyres = ''; + $scope.newCar.skins = []; + } + + $scope.submitCar = function() { + if ($scope.newCar.$valid !== true) { + createAlert('warning', 'Car is not valid! Please try again!', 'pe-7s-close-circle'); + return; + } + + var car = _.pick($scope.newCar, ['name', 'data', 'mod_tyres', 'skins']); + $q.when($scope.uploadCar(car)).then(function(results) { + createAlert('success', 'Car succesfully added!', 'pe-7s-star'); + CarService.GetCars(function (data) { + $scope.cars = data; + }); + }, function(reason) { + createAlert('alert', 'Failed to add car - ' + reason, 'pe-7s-close-circle'); + }); + $scope.files = []; + $scope.userDropped = false; + $scope.resetNewCar(); + } + + $scope.uploadCar = function(car, progressCb) { + var uploadPromise = Upload.upload({ + url: '/api/cars', + data: { car: car } + }); + + return uploadPromise.then(function(response) { + return $timeout(function() { + return { success: true, car: car, result: response.data }; + }); + }, function(response) { + if (response.status > 0) { + var errorMsg = response.status + ': ' + response.data; + return { success: false, car: car, result: errorMsg }; + } + }, progressCb); + } + + $scope.validateCar = function(files) { + if (files.length === 0) { + return + } + $scope.resetNewCar(); + + $scope.userDropped = true; + + var directories = _.filter(files, function(file) { + return file.type === 'directory'; + }); + // Car name + $scope.newCar.name = directories[0].path.split('/')[0]; + $scope.newCar.mod_tyres += '[' + $scope.newCar.name + ']\n'; + $scope.newCar.mod_tyres += 'S=Slick Soft\nM=Slick Medium\nH=Slick Hard'; + // Car skins + $scope.newCar.skins = _.map(_.filter(directories, function(dir) { + var parts = dir.path.split('/'); + return parts.length === 3 && parts[1] === 'skins'; + }), function(skinDir) { + return skinDir.path.split('/')[2]; + }); + if ($scope.newCar.skins.length === 0) { + createAlert('warning', + 'Dropped car directory has no skins!', + 'pe-7s-close-circle'); + return + } + // Car data.acd + var candidates = _.filter(files, function(file) { + return file.path === $scope.newCar.name + '/data.acd'; + }); + if (candidates.length === 1) { + $scope.newCar.data = [candidates[0]]; + } else { + candidates = _.filter(directories, function(dir) { + return dir.path === $scope.newCar.name + '/data'; + }); + if (candidates.length !== 1) { + createAlert('warning', + 'Dropped car directory has neither data.acd nor data/-directory!', + 'pe-7s-close-circle'); + return + } + $scope.newCar.data = _.filter(files, function(file) { + return file.type !== 'directory' && file.path.startsWith($scope.newCar.name + '/data'); + }); + } + $scope.newCar.$valid = true; + } + + function createAlert(type, msg, icon) { + $.notify({ + icon: icon, + message: msg + },{ + type: type, + timer: 3000 + }); + } + }) + .controller('TrackCtrl', function($scope, Upload, $timeout, $q, TrackService) { + $scope.alerts = []; + $scope.files = []; + $scope.trackItems = [ + { name: 'surfaces', filename: 'surfaces.ini', subdir: 'data', required: true, max_size: 1000000 }, + { name: 'drs_zones', filename: 'drs_zones.ini', subdir: 'data', required: false, max_size: 1000000 }, + { name: 'preview', filename: 'preview.png', subdir: 'ui', required: true, max_size: 5000000 }, + { name: 'ui_track', filename: 'ui_track.json', subdir: 'ui', required: true, max_size: 1000000 } + ]; + $scope.newTrack = { + name: '', + layouts: [], + errors: [], + $valid: false + }; + $scope.userDropped = false; + + TrackService.GetTracks(function (data) { + $scope.tracks = data; + }); + + $scope.$watch('files', function() { + $scope.validateTrack($scope.files); + }); + + $scope.removeTrack = function(index) { + if (!confirm('Are you sure?')) { + return; + } + try { + var track = $scope.tracks[index]; + TrackService.RemoveTrack(track.name, function(result) { + if (!(result[0] === 'O' && result[1] === 'K')) { + createAlert('warning', 'Remove failed', 'pe-7s-close-circle'); + } else { + $scope.tracks.splice(index, 1); + createAlert('success', 'Removed succesfully', 'pe-7s-star'); + } + }); + } catch(e) { + console.log('Error - ' + e); + } + } + + $scope.resetNewTrack = function() { + $scope.newTrack.name = ''; + $scope.newTrack.layouts = []; + $scope.newTrack.errors = []; + $scope.newTrack.$valid = false; + } + + $scope.submitTrack = function() { + if ($scope.newTrack.$valid !== true) { + createAlert('warning', 'Track is not valid! Please try again!', 'pe-7s-close-circle'); + return; + } + + var track = _.pick($scope.newTrack, ['name', 'layouts']); + $q.when($scope.uploadTrack(track)).then(function(results) { + createAlert('success', 'Track succesfully added!', 'pe-7s-star'); + TrackService.GetTracks(function (data) { + $scope.tracks = data; + }); + }, function(reason) { + createAlert('warning', 'Failed to add track - ' + reason, 'pe-7s-close-circle'); + }); + $scope.files = [] + $scope.userDropped = false; + $scope.resetNewTrack(); + } + + $scope.uploadTrack = function(track, progressCb) { + var uploadPromise = Upload.upload({ + url: '/api/tracks', + data: { track: track } + }); + + return uploadPromise.then(function(response) { + return $timeout(function() { + return { success: true, track: track, result: response.data }; + }); + }, function(response) { + if (response.status > 0) { + var errorMsg = response.status + ': ' + response.data; + return { success: false, track: track, result: errorMsg }; + } + }, progressCb); + } + + function validateLayoutFile(files, subdir, item, errorCb) { + var candidates = _.filter(files, function(file) { + return file.path === subdir + item.filename; + }); + if (candidates.length < 1) { + if (item.required) { + $scope.newTrack.$valid = false; + } + errorCb(item.name, 'found'); + } else if (candidates > 1) { + $scope.newTrack.$valid = false; + errorCb(item.name, 'multiple'); + } else { + if (candidates[0].size > item.max_size) { + $scope.newTrack.$valid = false; + errorCb(item.name, 'max_size'); + } else { + return candidates[0]; + } + } + return null; + } + + function addLayoutError(idx, key, errorKey) { + if ($scope.newTrack.errors.length <= idx) { + $scope.newTrack.errors[idx] = {}; + } + if (!_.has($scope.newTrack.errors[idx], key)) { + $scope.newTrack.errors[idx][key] = {}; + } + $scope.newTrack.errors[idx][key][errorKey] = true; + } + + $scope.validateTrack = function(files) { + if (files.length === 0) { + return; + } + $scope.resetNewTrack(); + + $scope.userDropped = true; + $scope.newTrack.$valid = true; + + var directories = _.filter(files, function(file) { + return file.type === 'directory'; + }); + // Track name + $scope.newTrack.name = directories[0].path.split('/')[0]; + // Track layouts + var hasMultipleLayouts = _.indexOf( + _.map(directories, 'path'), $scope.newTrack.name + '/data') === -1; + if (hasMultipleLayouts) { + var layoutNames = _.map(_.filter(directories, isLayoutDir), function(dir) { + return dir.path.split('/')[1]; + }); + var idx = 0; + _.forEach(layoutNames, function(layoutName) { + var layout = { name: layoutName }; + var errorCb = _.partial(addLayoutError, idx); + _.forEach($scope.trackItems, function(item) { + // Multilayout directory structure: + // TRACK/LAYOUT/data/ + // TRACK/ui/LAYOUT/ + var subdir = $scope.newTrack.name + '/' + + (item.subdir == 'ui' ? 'ui/' + layoutName : layoutName + '/data') + '/'; + var candidate = validateLayoutFile(files, subdir, item, errorCb); + if (candidate !== null && candidate !== undefined) { + layout[item.name] = candidate; + } + }); + $scope.newTrack.layouts[idx] = layout; + idx++; + }); + } else { + var layout = { name: null }; + _.forEach($scope.trackItems, function(item) { + var subdir = $scope.newTrack.name + '/' + item.subdir + '/'; + var errorCb = _.partial(addLayoutError, 0); + var candidate = validateLayoutFile(files, subdir, item, errorCb); + if (candidate !== null && candidate !== undefined) { + layout[item.name] = candidate; + } + }); + $scope.newTrack.layouts[0] = layout; + } + } + + function isLayoutDir(dir) { + var reservedNames = ['ui', 'ai', 'skins', 'data']; + var parts = dir.path.split('/'); + if (parts.length !== 2) { + return false; + } else if (parts[0] !== $scope.newTrack.name) { + return false; + } else if (_.indexOf(reservedNames, parts[1]) !== -1) { + return false; + } else { + return true; + } + } + + function createAlert(type, msg, icon) { + $.notify({ + icon: icon, + message: msg + },{ + type: type, + timer: 3000 + }); + } + }) .controller('RulesCtrl', function($scope, $timeout, ServerService, DynamicTrackService) { $scope.alerts = []; @@ -662,7 +1098,7 @@ angular.module('acServerManager') $scope.$broadcast('show-errors-check-validity'); if ($scope.form.$invalid) { - createAlert('warning', 'There are errors on the form', true); + createAlert('warning', 'There are errors on the form', 'pe-7s-note'); return; } @@ -693,23 +1129,23 @@ angular.module('acServerManager') }); if (saved) { - createAlert('success', 'Saved successfully', true); - } else { - reateAlert('success', 'Save failed', true); + createAlert('success', 'Saved successfully', 'pe-7s-star'); + } else { + createAlert('warning', 'Save failed', 'pe-7s-close-circle'); } } catch (e) { console.log('Error - ' + e); } } - function createAlert(type, msg, autoClose) { - var alert = { type: type, msg: msg}; - $scope.alerts.push(alert); - if (autoClose) { - $timeout(function(){ - $scope.alerts.splice($scope.alerts.indexOf(alert), 1); - }, 3000); - } + function createAlert(type, msg, icon) { + $.notify({ + icon: icon, + message: msg + },{ + type: type, + timer: 3000 + }); } }) .controller('AdvancedCtrl', function($scope, $timeout, ServerService) { @@ -726,7 +1162,7 @@ angular.module('acServerManager') $scope.$broadcast('show-errors-check-validity'); if ($scope.form.$invalid) { - createAlert('warning', 'There are errors on the form', true); + createAlert('warning', 'There are errors on the form', 'pe-7s-note'); return; } @@ -738,9 +1174,9 @@ angular.module('acServerManager') ServerService.SaveServerDetails($scope.server, function(result) { if (result[0] === 'O' && result[1] === 'K') { - createAlert('success', 'Saved successfully', true); + createAlert('success', 'Saved successfully', 'pe-7s-star'); } else { - createAlert('warning', 'Save failed', true); + createAlert('warning', 'Save failed', 'pe-7s-close-circle'); } }); } catch (e) { @@ -749,15 +1185,15 @@ angular.module('acServerManager') } - function createAlert(type, msg, autoClose) { - var alert = { type: type, msg: msg}; - $scope.alerts.push(alert); - if (autoClose) { - $timeout(function(){ - $scope.alerts.splice($scope.alerts.indexOf(alert), 1); - }, 3000); - } + function createAlert(type, msg, icon) { + $.notify({ + icon: icon, + message: msg + },{ + type: type, + timer: 3000 + }); } }) .controller('HelpCtrl', function($scope) { - }); \ No newline at end of file + }); diff --git a/frontend/app/services.js b/frontend/app/services.js index 1360576..7d560a3 100644 --- a/frontend/app/services.js +++ b/frontend/app/services.js @@ -1,6 +1,6 @@ 'use strict'; -angular.module('acServerManager.services', ['ngResource']). +angular.module('acServerManager.services', ['ngResource', 'ngFileUpload']). factory('CarService', function($resource) { return { GetCars: function(callback) { @@ -14,6 +14,12 @@ angular.module('acServerManager.services', ['ngResource']). var result = resource.get({car: car}, function() { callback(result); }); + }, + RemoveCar: function(car, callback) { + var resource = $resource('/api/cars/:car'); + var result = resource.delete({car: car}, function() { + callback(result); + }); } }; }). @@ -41,7 +47,13 @@ angular.module('acServerManager.services', ['ngResource']). callback(null); }); } - } + }, + RemoveTrack: function(track, callback) { + var resource = $resource('/api/tracks/:track'); + var result = resource.delete({track: track}, function() { + callback(result); + }); + }, }; }). factory('ServerService', function($resource) { @@ -275,4 +287,32 @@ angular.module('acServerManager.services', ['ngResource']). }); } }; - }); \ No newline at end of file + }). + factory('TemplateService', function($resource) { + return { + GetTemplates: function(callback) { + var resource = $resource('/api/templates'); + var result = resource.query(function() { + callback(result); + }); + }, + LoadTemplate: function(template, callback) { + var resource = $resource('/api/templates/:uuid'); + var result = resource.save({uuid: template.uuid}, template, function() { + callback(result); + }); + }, + RemoveTemplate: function(template, callback) { + var resource = $resource('/api/templates/:uuid'); + var result = resource.delete({uuid: template.uuid}, function() { + callback(result); + }); + }, + SaveCurrent: function(template, callback) { + var resource = $resource('/api/templates'); + var result = resource.save(template, function() { + callback(result); + }); + } + }; + }); diff --git a/frontend/cars.html b/frontend/cars.html new file mode 100644 index 0000000..8fa577c --- /dev/null +++ b/frontend/cars.html @@ -0,0 +1,254 @@ + + +
+ + + + +
+ + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + +