Better error reporting and new validator support attached to whole uci section

This commit is contained in:
Martin Schröder 2015-05-28 17:05:57 +02:00 committed by Martin Schröder
parent 98e0c2abd3
commit 2275454efa
8 changed files with 69 additions and 21 deletions

View file

@ -122,7 +122,7 @@ JUCI.app.config(function ($stateProvider, $locationProvider, $compileProvider, $
$rootScope.errors = [];
$rootScope.$on("error", function(ev, data){
$rootScope.errors.push({message: data});
console.log("ERROR: "+ev.name+": "+JSON.stringify(Object.keys(ev.currentScope)));
//console.log("ERROR: "+ev.name+": "+JSON.stringify(Object.keys(ev.currentScope)));
});
// set current language
gettextCatalog.currentLanguage = "en";

View file

@ -283,10 +283,14 @@
return deferred.promise();
}
/*
UCISection.prototype.$save = function(){
var deferred = $.Deferred();
var self = this;
// try to validate the section using section wide validator
if(self[".validator"] instanceof Function) self[".validator"](self);
$rpc.uci.set({
config: self[".config"][".name"],
section: self[".name"],
@ -297,7 +301,7 @@
deferred.reject();
});
return deferred.promise();
}
}*/
UCISection.prototype.$delete = function(){
var self = this;
@ -326,6 +330,9 @@
if(!type) return {};
var self = this;
var changed = {};
if(type[".validator"] instanceof Function) type[".validator"](self);
Object.keys(type).map(function(k){
if(self[k] && self[k].dirty){
//console.log("Adding dirty field: "+k);
@ -443,12 +450,13 @@
});
}
UCIConfig.prototype.$registerSectionType = function(name, descriptor){
UCIConfig.prototype.$registerSectionType = function(name, descriptor, validator){
var config = this[".name"];
var conf_type = section_types[config];
if(typeof conf_type === "undefined") conf_type = section_types[config] = {};
conf_type[name] = descriptor;
this["@"+name] = [];
if(validator !== undefined && validator instanceof Function) conf_type[name][".validator"] = validator;
console.log("Registered new section type "+config+"."+name);
}

View file

@ -75,19 +75,30 @@ $juci.module("core")
'<button class="btn btn-lg btn-primary" ng-click="onApply()" ng-disabled="busy"><i class="fa fa-spinner" ng-show="busy"/>{{ "Apply"| translate }}</button><button class="btn btn-lg btn-default" ng-click="onCancel()">{{ "Cancel" | translate }}</button>'+
'</div><div style="clear: both;"></div></div>',
replace: true,
scope: {
onPreApply: "&"
},
controller: "luciConfigApplyController"
};
}).controller("luciConfigApplyController", function($scope, $uci){
$scope.onApply = function(){
if($scope.onPreApply) $scope.onPreApply();
$scope.busy = 1;
$uci.save().done(function(){
console.log("Saved uci configuration!");
}).fail(function(){
console.error("Could not save uci configuration!");
}).always(function(){
try {
$uci.save().done(function(){
console.log("Saved uci configuration!");
}).fail(function(){
console.error("Could not save uci configuration!");
}).always(function(){
$scope.busy = 0;
setTimeout(function(){$scope.$apply();}, 0);
});
} catch(e){
$scope.busy = 0;
setTimeout(function(){$scope.$apply();}, 0);
});
$scope.$emit("error", e.message);
console.error("Error while applying config: "+e.message);
}
}
$scope.onCancel = function(){
// simple way to reset

View file

@ -1,5 +1,5 @@
<div class="alert alert-danger" ng-show="errors.length">
<ul>
<li ng-repeat="err in errors"><button class="btn btn-default pull-right">Hide</button>{{err.message}}<div style="clear: both;"></div></li>
<li ng-repeat="err in errors track by $index"><!--<button class="btn btn-default pull-right" >Hide</button>-->{{(err.message||err)}}<div style="clear: both;"></div></li>
</ul>
</div>

View file

@ -4,6 +4,7 @@ JUCI.app
return {
// accepted parameters for this tag
scope: {
ngModel: "="
},
templateUrl: plugin_root+"/widgets/luci.errors.html",
replace: true,
@ -11,6 +12,6 @@ JUCI.app
};
})
.controller("luciErrors", function($scope, $rootScope, $localStorage){
$scope.errors = $rootScope.errors;
if($scope.ngModel) $scope.errors = $scope.ngModel;
else $scope.errors = $rootScope.errors;
});

View file

@ -19,7 +19,7 @@
</luci-config-lines>
<luci-config-lines ng-hide="interface.disabled.value">
<luci-config-line title="{{'wifi-iface.ssid'|translate}}">
<input type="text" class="form-control" placeholder="Wifi Name" ng-model="interface.ssid.value"/>
<input type="text" class="form-control" placeholder="Wifi Name" ng-model="interface.ssid.value" maxlength="32"/>
</luci-config-line>
<luci-config-line title="{{'wifi-iface.closed'|translate}}">
<switch id="enabled" name="enabled" ng-model="interface.closed.value" class="green" inverted></switch>
@ -30,17 +30,18 @@
<luci-config-line title="{{'wifi-iface.encryption'|translate}}">
<luci-select ng-model="interface.encryption.value" ng-items="cryptoChoices" placeholder="Choose Protection"/>
</luci-config-line>
<luci-config-line title="{{'wifi-iface.key'|translate}}">
<input type="{{(!showPassword)?'password':'text'}}" class="form-control" placeholder="{{'wifi-iface.key'|translate}}" ng-model="interface.key.value"/>
<div class="checkbox checkbox-info">
<input type="checkbox" ng-model="showPassword" />
<label><strong>{{'Display Characters'|translate}}</strong></label>
</div>
<luci-config-line title="{{'wifi-iface.key'|translate}}" ng-show="interface.encryption.value != 'none'">
<input type="{{(!showPassword)?'password':'text'}}" class="form-control" placeholder="{{'wifi-iface.key'|translate}}" ng-model="interface.key.value" />
<div class="checkbox checkbox-info">
<input type="checkbox" ng-model="showPassword" />
<label><strong>{{'Display Characters'|translate}}</strong></label>
</div>
</luci-config-line>
</luci-config-lines>
<luci-errors ng-model="errors"/>
</div>
<div class="panel-footer" ng-show="expanded">
<luci-config-apply></luci-config-apply>
<luci-config-apply on-pre-apply="onPreApply()"></luci-config-apply>
</div>
</div>
</div>

View file

@ -11,6 +11,11 @@ $juci.module("wifi")
require: "^ngModel"
};
}).controller("WifiInterfaceController", function($scope, $uci, gettext){
$scope.errors = [];
$scope.$on("error", function(ev, err){
ev.stopPropagation();
$scope.errors.push(err);
});
$scope.$watch("interface", function(value){
try {
$scope.cryptoChoices = $scope.interface.encryption.schema.allow;
@ -26,5 +31,8 @@ $juci.module("wifi")
x[".frequency"] = dev[".label"];
});
$scope.title = "wifi-iface.name="+$scope.interface[".name"];
});
});
$scope.onPreApply = function(){
$scope.errors.length = 0;
}
});

View file

@ -67,6 +67,25 @@ JUCI.app
"macmode": { dvalue: 1, type: Number, allow: [ 0, 1, 2 ] },
"macfilter": { dvalue: false, type: Boolean },
"maclist": { dvalue: [], type: Array, match_each: /^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/ }
}, function validator(section){
// validate ssid
if(section.ssid.value.length >= 32)
throw new Error("SSID string can be at most 32 characters long!");
// validate keys
switch(section.encryption.value){
case "wep": {
if(!section.key.value || !section.key.value.match(/[a-f0-9A-F]{10,26}/))
throw new Error("WEP encryption key must be 10-26 hexadecimal characters!");
} break;
case "psk":
case "psk2":
case "mixed-psk": {
if(!section.key.value || !(section.key.value.length > 8 && section.key.value.length < 64))
throw new Error("WPA key must be 8-63 characters long!");
} break;
default:
break;
}
});