Updated docs
with array field
Change-Id: Ie707c58a0c38afe30fed776f0d1c16fb777b7457
diff --git a/.eslintrc b/.eslintrc
index ba3aaee..d580f3a 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -37,7 +37,9 @@
"angular/ng_di": [0, "function or array"],
"angular/ng_angularelement": 0,
"angular/ng_on_watch": 1,
- "angular/ng_controller_as_vm": 0
+ "angular/ng_controller_as_vm": 0,
+ "angular/ng_controller_as": 2,
+ "angular/ng_on_watch": 0,
},
"globals" :{
"angular": true
diff --git a/dist/ngXosHelpers.min.js b/dist/ngXosHelpers.min.js
index 2c8fe7a..271d3a8 100644
--- a/dist/ngXosHelpers.min.js
+++ b/dist/ngXosHelpers.min.js
@@ -1,2 +1,2 @@
-"use strict";function _toConsumableArray(e){if(Array.isArray(e)){for(var n=0,i=Array(e.length);n<e.length;n++)i[n]=e[n];return i}return Array.from(e)}!function(){angular.module("xos.uiComponents",["chart.js","RecursionHelper","dndLists"])}(),function(){angular.module("xos.uiComponents").component("xosSmartTable",{restrict:"E",bindings:{config:"="},template:'\n <div class="row" ng-show="vm.data.length > 0">\n <div class="col-xs-12 text-right">\n <a href="" class="btn btn-success" ng-click="vm.createItem()">\n Add\n </a>\n </div>\n </div>\n <div class="row">\n <div class="col-xs-12 table-responsive">\n <xos-table config="vm.tableConfig" data="vm.data"></xos-table>\n </div>\n </div>\n <div class="panel panel-default" ng-show="vm.detailedItem">\n <div class="panel-heading">\n <div class="row">\n <div class="col-xs-11">\n <h3 class="panel-title" ng-show="vm.detailedItem.id">Update {{vm.config.resource}} {{vm.detailedItem.id}}</h3>\n <h3 class="panel-title" ng-show="!vm.detailedItem.id">Create {{vm.config.resource}} item</h3>\n </div>\n <div class="col-xs-1">\n <a href="" ng-click="vm.cleanForm()">\n <i class="glyphicon glyphicon-remove pull-right"></i>\n </a>\n </div>\n </div>\n </div>\n <div class="panel-body">\n <xos-form config="vm.formConfig" ng-model="vm.detailedItem"></xos-form>\n </div>\n </div>\n <xos-alert config="{type: \'success\', closeBtn: true}" show="vm.responseMsg">{{vm.responseMsg}}</xos-alert>\n <xos-alert config="{type: \'danger\', closeBtn: true}" show="vm.responseErr">{{vm.responseErr}}</xos-alert>\n ',bindToController:!0,controllerAs:"vm",controller:["$injector","LabelFormatter","_","XosFormHelpers",function(e,n,i,o){var t=this;this.responseMsg=!1,this.responseErr=!1,this.tableConfig={columns:[],actions:[{label:"delete",icon:"remove",cb:function(e){t.Resource["delete"]({id:e.id}).$promise.then(function(){i.remove(t.data,function(n){return n.id===e.id}),t.responseMsg=t.config.resource+" with id "+e.id+" successfully deleted"})["catch"](function(n){t.responseErr=n.data.detail||"Error while deleting "+t.config.resource+" with id "+e.id})},color:"red"},{label:"details",icon:"search",cb:function(e){t.detailedItem=e}}],classes:"table table-striped table-bordered table-responsive",filter:"field",order:!0,pagination:{pageSize:10}},this.formConfig={exclude:this.config.hiddenFields,fields:{},formName:this.config.resource+"Form",actions:[{label:"Save",icon:"ok",cb:function(e){var n=void 0,i=!0;e.id?(n=e.$update(),i=!1):n=e.$save(),n.then(function(n){i&&t.data.push(angular.copy(n)),delete t.detailedItem,t.responseMsg=t.config.resource+" with id "+e.id+" successfully saved"})["catch"](function(n){t.responseErr=n.data.detail||"Error while saving "+t.config.resource+" with id "+e.id})},"class":"success"}]},this.cleanForm=function(){delete t.detailedItem},this.createItem=function(){t.detailedItem=new t.Resource},this.Resource=e.get(this.config.resource);var r=function(){t.Resource.query().$promise.then(function(e){if(!e[0])return void(t.data=e);var r=e[0],a=Object.keys(r);i.remove(a,function(e){return"id"===e||"validators"===e}),angular.isArray(t.config.hiddenFields)&&(a=i.difference(a,t.config.hiddenFields)),a.forEach(function(e){var i={label:n.format(e),prop:e};i.type=o._getFieldFormat(r[e]),t.tableConfig.columns.push(i)}),a.forEach(function(e){t.formConfig.fields[e]={label:n.format(e).replace(":",""),type:o._getFieldFormat(r[e])}}),t.data=e})};r()}]})}(),function(){angular.module("xos.uiComponents").component("xosSmartPie",{restrict:"E",bindings:{config:"="},template:'\n <canvas\n class="chart chart-pie {{vm.config.classes}}"\n chart-data="vm.data" chart-labels="vm.labels"\n chart-legend="{{vm.config.legend}}">\n </canvas>\n ',bindToController:!0,controllerAs:"vm",controller:["$injector","$interval","$scope","$timeout","_",function(e,n,i,o,t){var r=this;if(!this.config.resource&&!this.config.data)throw new Error("[xosSmartPie] Please provide a resource or an array of data in the configuration");var a=function(e){return t.groupBy(e,r.config.groupBy)},s=function(e){return t.reduce(Object.keys(e),function(n,i){return n.concat(e[i].length)},[])},l=function(e){return angular.isFunction(r.config.labelFormatter)?r.config.labelFormatter(Object.keys(e)):Object.keys(e)},c=function(e){var n=a(e);r.data=s(n),r.labels=l(n)};this.config.resource?!function(){r.Resource=e.get(r.config.resource);var i=function(){r.Resource.query().$promise.then(function(e){e[0]&&c(e)})};i(),r.config.poll&&n(function(){i()},1e3*r.config.poll)}():i.$watch(function(){return r.config.data},function(e){e&&c(r.config.data)},!0),i.$on("create",function(e,n){console.log("create: "+n.id)}),i.$on("destroy",function(e,n){console.log("destroy: "+n.id)})}]})}(),function(){angular.module("xos.uiComponents").component("xosValidation",{restrict:"E",bindings:{field:"=",form:"="},template:'\n <div ng-cloak>\n <xos-alert config="vm.config" show="vm.field.$error.required !== undefined && vm.field.$error.required !== false && (vm.field.$touched || vm.form.$submitted)">\n Field required\n </xos-alert>\n <xos-alert config="vm.config" show="vm.field.$error.email !== undefined && vm.field.$error.email !== false && (vm.field.$touched || vm.form.$submitted)">\n This is not a valid email\n </xos-alert>\n <xos-alert config="vm.config" show="vm.field.$error.minlength !== undefined && vm.field.$error.minlength !== false && (vm.field.$touched || vm.form.$submitted)">\n Too short\n </xos-alert>\n <xos-alert config="vm.config" show="vm.field.$error.maxlength !== undefined && vm.field.$error.maxlength !== false && (vm.field.$touched || vm.form.$submitted)">\n Too long\n </xos-alert>\n <xos-alert config="vm.config" show="vm.field.$error.custom !== undefined && vm.field.$error.custom !== false && (vm.field.$touched || vm.form.$submitted)">\n Field invalid\n </xos-alert>\n </div>\n ',transclude:!0,bindToController:!0,controllerAs:"vm",controller:function(){this.config={type:"danger"}}})}(),function(){angular.module("xos.uiComponents").component("xosTable",{restrict:"E",bindings:{data:"=",config:"="},template:'\n <div ng-show="vm.data.length > 0 && vm.loader == false">\n <div class="row" ng-if="vm.config.filter == \'fulltext\'">\n <div class="col-xs-12">\n <input\n class="form-control"\n placeholder="Type to search.."\n type="text"\n ng-model="vm.query"/>\n </div>\n </div>\n <table ng-class="vm.classes" ng-hide="vm.data.length == 0">\n <thead>\n <tr>\n <th ng-repeat="col in vm.columns">\n {{col.label}}\n <span ng-if="vm.config.order">\n <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = false">\n <i class="glyphicon glyphicon-chevron-up"></i>\n </a>\n <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = true">\n <i class="glyphicon glyphicon-chevron-down"></i>\n </a>\n </span>\n </th>\n <th ng-if="vm.config.actions">Actions:</th>\n </tr>\n </thead>\n <tbody ng-if="vm.config.filter == \'field\'">\n <tr>\n <td ng-repeat="col in vm.columns">\n <input\n ng-if="col.type !== \'boolean\' && col.type !== \'array\' && col.type !== \'object\' && col.type !== \'custom\'"\n class="form-control"\n placeholder="Type to search by {{col.label}}"\n type="text"\n ng-model="vm.query[col.prop]"/>\n <select\n ng-if="col.type === \'boolean\'"\n class="form-control"\n ng-model="vm.query[col.prop]">\n <option value="">-</option>\n <option value="true">True</option>\n <option value="false">False</option>\n </select>\n </td>\n <td ng-if="vm.config.actions"></td>\n </tr>\n </tbody>\n <tbody>\n <tr ng-repeat="item in vm.data | filter:vm.query:vm.comparator | orderBy:vm.orderBy:vm.reverse | pagination:vm.currentPage * vm.config.pagination.pageSize | limitTo: (vm.config.pagination.pageSize || vm.data.length) track by $index">\n <td ng-repeat="col in vm.columns" xos-link-wrapper>\n <span ng-if="!col.type || col.type === \'text\'">{{item[col.prop]}}</span>\n <span ng-if="col.type === \'boolean\'">\n <i class="glyphicon"\n ng-class="{\'glyphicon-ok\': item[col.prop], \'glyphicon-remove\': !item[col.prop]}">\n </i>\n </span>\n <span ng-if="col.type === \'date\'">\n {{item[col.prop] | date:\'H:mm MMM d, yyyy\'}}\n </span>\n <span ng-if="col.type === \'array\'">\n {{item[col.prop] | arrayToList}}\n </span>\n <span ng-if="col.type === \'object\'">\n <dl class="dl-horizontal">\n <span ng-repeat="(k,v) in item[col.prop]">\n <dt>{{k}}</dt>\n <dd>{{v}}</dd>\n </span>\n </dl>\n </span>\n <span ng-if="col.type === \'custom\'">\n {{col.formatter(item)}}\n </span>\n <span ng-if="col.type === \'icon\'">\n <i class="glyphicon glyphicon-{{col.formatter(item)}}">\n </i>\n </span>\n </td>\n <td ng-if="vm.config.actions">\n <a href=""\n ng-repeat="action in vm.config.actions"\n ng-click="action.cb(item)"\n title="{{action.label}}">\n <i\n class="glyphicon glyphicon-{{action.icon}}"\n style="color: {{action.color}};"></i>\n </a>\n </td>\n </tr>\n </tbody>\n </table>\n <xos-pagination\n ng-if="vm.config.pagination"\n page-size="vm.config.pagination.pageSize"\n total-elements="vm.data.length"\n change="vm.goToPage">\n </xos-pagination>\n </div>\n <div ng-show="(vm.data.length == 0 || !vm.data) && vm.loader == false">\n <xos-alert config="{type: \'info\'}">\n No data to show.\n </xos-alert>\n </div>\n <div ng-show="vm.loader == true">\n <div class="loader"></div>\n </div>\n ',bindToController:!0,controllerAs:"vm",controller:["_","$scope","Comparator",function(e,n,i){var o=this;if(this.comparator=i,this.loader=!0,n.$watch(function(){return o.data},function(e){angular.isDefined(e)&&(o.loader=!1)}),!this.config)throw new Error('[xosTable] Please provide a configuration via the "config" attribute');if(!this.config.columns)throw new Error("[xosTable] Please provide a columns list in the configuration");this.config.order&&angular.isObject(this.config.order)&&(this.reverse=this.config.order.reverse||!1,this.orderBy=this.config.order.field||"id");var t=e.filter(this.config.columns,{type:"custom"});angular.isArray(t)&&t.length>0&&e.forEach(t,function(e){if(!e.formatter||!angular.isFunction(e.formatter))throw new Error("[xosTable] You have provided a custom field type, a formatter function should provided too.")});var r=e.filter(this.config.columns,{type:"icon"});angular.isArray(r)&&r.length>0&&e.forEach(r,function(e){if(!e.formatter||!angular.isFunction(e.formatter))throw new Error("[xosTable] You have provided an icon field type, a formatter function should provided too.")});var a=e.filter(this.config.columns,function(e){return angular.isDefined(e.link)});angular.isArray(a)&&a.length>0&&e.forEach(a,function(e){if(!angular.isFunction(e.link))throw new Error("[xosTable] The link property should be a function.")}),this.columns=this.config.columns,this.classes=this.config.classes||"table table-striped table-bordered",this.config.actions,this.config.pagination&&(this.currentPage=0,this.goToPage=function(e){o.currentPage=e})}]}).filter("arrayToList",function(){return function(e){return angular.isArray(e)?e.join(", "):e}}).directive("xosLinkWrapper",function(){return{restrict:"A",transclude:!0,template:'\n <a ng-if="col.link" href="{{col.link(item)}}">\n <div ng-transclude></div>\n </a>\n <div ng-transclude ng-if="!col.link"></div>\n '}})}(),function(){angular.module("xos.uiComponents").component("xosPagination",{restrict:"E",bindings:{pageSize:"=",totalElements:"=",change:"="},template:'\n <div class="row" ng-if="vm.pageList.length > 1">\n <div class="col-xs-12 text-center">\n <ul class="pagination">\n <li\n ng-click="vm.goToPage(vm.currentPage - 1)"\n ng-class="{disabled: vm.currentPage == 0}">\n <a href="" aria-label="Previous">\n <span aria-hidden="true">«</span>\n </a>\n </li>\n <li ng-repeat="i in vm.pageList" ng-class="{active: i === vm.currentPage}">\n <a href="" ng-click="vm.goToPage(i)">{{i + 1}}</a>\n </li>\n <li\n ng-click="vm.goToPage(vm.currentPage + 1)"\n ng-class="{disabled: vm.currentPage == vm.pages - 1}">\n <a href="" aria-label="Next">\n <span aria-hidden="true">»</span>\n </a>\n </li>\n </ul>\n </div>\n </div>\n ',bindToController:!0,controllerAs:"vm",controller:["$scope",function(e){var n=this;this.currentPage=0,this.goToPage=function(e){e<0||e===n.pages||(n.currentPage=e,n.change(e))},this.createPages=function(e){for(var n=[],i=0;i<e;i++)n.push(i);return n},e.$watch(function(){return n.totalElements},function(){n.totalElements&&(n.pages=Math.ceil(n.totalElements/n.pageSize),n.pageList=n.createPages(n.pages))})}]}).filter("pagination",function(){return function(e,n){return e&&angular.isArray(e)?(n=parseInt(n,10),e.slice(n)):e}})}(),function(){angular.module("xos.uiComponents").component("xosForm",{restrict:"E",bindings:{config:"=",ngModel:"="},template:'\n <form name="vm.{{vm.config.formName || \'form\'}}" novalidate>\n <div class="form-group" ng-repeat="(name, field) in vm.formField">\n <xos-field name="name" field="field" ng-model="vm.ngModel[name]"></xos-field>\n <xos-validation field="vm[vm.config.formName || \'form\'][name]" form = "vm[vm.config.formName || \'form\']"></xos-validation>\n <div class="alert alert-info" ng-show="(field.hint).length >0" role="alert">{{field.hint}}</div>\n </div>\n <div class="form-group" ng-if="vm.config.actions">\n <xos-alert config="vm.config.feedback" show="vm.config.feedback.show">{{vm.config.feedback.message}}</xos-alert>\n\n <button role="button" href=""\n ng-repeat="action in vm.config.actions"\n ng-click="action.cb(vm.ngModel, vm[vm.config.formName || \'form\'])"\n class="btn btn-{{action.class}}"\n title="{{action.label}}">\n <i class="glyphicon glyphicon-{{action.icon}}"></i>\n {{action.label}}\n </button>\n </div>\n </form>\n ',bindToController:!0,controllerAs:"vm",controller:["$scope","$log","_","XosFormHelpers",function(e,n,i,o){var t=this;if(!this.config)throw new Error('[xosForm] Please provide a configuration via the "config" attribute');if(!this.config.actions)throw new Error("[xosForm] Please provide an action list in the configuration");this.config.feedback||(this.config.feedback={show:!1,message:"Form submitted successfully !!!",type:"success"}),this.excludedField=["id","validators","created","updated","deleted","backend_status"],this.config&&this.config.exclude&&(this.excludedField=this.excludedField.concat(this.config.exclude)),this.formField=[],e.$watch(function(){return t.config},function(){if(t.ngModel){var e=i.difference(Object.keys(t.ngModel),t.excludedField),n=o.parseModelField(e);t.formField=o.buildFormStructure(n,t.config.fields,t.ngModel)}},!0),e.$watch(function(){return t.ngModel},function(e){if(t.formField={},e){var n=i.difference(Object.keys(e),t.excludedField),r=o.parseModelField(n);t.formField=o.buildFormStructure(r,t.config.fields,e,t.config.order)}})}]})}(),function(){angular.module("xos.uiComponents").component("xosField",{restrict:"E",bindings:{name:"=",field:"=",ngModel:"="},template:'\n <label ng-if="vm.field.type !== \'object\' && vm.field.type !== \'array\'">{{vm.field.label}}</label>\n <input\n xos-custom-validator custom-validator="vm.field.validators.custom || null"\n ng-if="vm.field.type !== \'boolean\' && vm.field.type !== \'object\' && vm.field.type !== \'select\' && vm.field.type !== \'array\'"\n type="{{vm.field.type}}"\n name="{{vm.name}}"\n class="form-control"\n ng-model="vm.ngModel"\n ng-minlength="vm.field.validators.minlength || 0"\n ng-maxlength="vm.field.validators.maxlength || 2000"\n ng-required="vm.field.validators.required || false" />\n <select class="form-control" ng-if ="vm.field.type === \'select\'"\n name = "{{vm.name}}"\n ng-options="item.id as item.label for item in vm.field.options"\n ng-model="vm.ngModel"\n ng-required="vm.field.validators.required || false">\n </select>\n <span class="boolean-field" ng-if="vm.field.type === \'boolean\'">\n <a href="#"\n class="btn btn-success"\n ng-show="vm.ngModel"\n ng-click="vm.ngModel = false">\n <i class="glyphicon glyphicon-ok"></i>\n </a>\n <a href="#"\n class="btn btn-danger"\n ng-show="!vm.ngModel"\n ng-click="vm.ngModel = true">\n <i class="glyphicon glyphicon-remove"></i>\n </a>\n </span>\n <div\n class="panel panel-default object-field"\n ng-if="vm.field.type == \'object\' && (!vm.isEmptyObject(vm.ngModel) || !vm.isEmptyObject(vm.field.properties))"\n >\n <div class="panel-heading">{{vm.field.label}}</div>\n <div class="panel-body">\n <div ng-if="!vm.field.properties" ng-repeat="(k, v) in vm.ngModel">\n <xos-field\n name="k"\n field="{label: vm.formatLabel(k), type: vm.getType(v)}"\n ng-model="v">\n </xos-field>\n </div>\n <div ng-if="vm.field.properties" ng-repeat="(k, v) in vm.field.properties">\n <xos-field\n name="k"\n field="{\n label: v.label || vm.formatLabel(k),\n type: v.type,\n validators: v.validators\n }"\n ng-model="vm.ngModel[k]">\n </xos-field>\n </div>\n </div>\n </div>\n <div\n class="panel panel-default array-field"\n ng-if="vm.field.type == \'array\'">\n <div class="panel-heading">{{vm.field.label}}</div>\n <div class="panel-body selected">\n <ul class="draggable" dnd-list="vm.ngModel">\n <li\n class="array-element"\n ng-repeat="item in vm.ngModel"\n dnd-draggable="item"\n dnd-moved="vm.ngModel.splice($index, 1)"\n dnd-effect-allowed="move"\n dnd-selected="models.selected = item"\n >\n <div class="well well-sm text-center">\n {{item}}\n </div>\n </li>\n <div class="clearfix"></div>\n </ul>\n </div>\n <div class="panel-body unselected">\n <ul class="draggable" dnd-list="vm.field.availableOptions">\n <li\n class="array-element"\n ng-repeat="item in vm.field.availableOptions"\n dnd-draggable="item"\n dnd-moved="vm.field.availableOptions.splice($index, 1)"\n dnd-effect-allowed="move"\n dnd-selected="models.selected = item"\n >\n <div class="well well-sm text-center">\n {{item}}\n </div>\n </li>\n <div class="clearfix"></div>\n </ul>\n </div>\n </div>\n ',bindToController:!0,controllerAs:"vm",controller:["$attrs","$scope","XosFormHelpers","LabelFormatter","_",function(e,n,i,o,t){var r=this;if(!this.name)throw new Error("[xosField] Please provide a field name");if(!this.field)throw new Error("[xosField] Please provide a field definition");if(!this.field.type)throw new Error("[xosField] Please provide a type in the field definition");if(!e.ngModel)throw new Error("[xosField] Please provide an ng-model");this.getType=i._getFieldFormat,this.formatLabel=o.format,this.isEmptyObject=function(e){return!e||0===Object.keys(e).length},"array"===this.field.type&&n.$watch(function(){return r.ngModel.length},function(){r.field.availableOptions=t.difference(r.field.options,r.ngModel)})}]}).directive("xosCustomValidator",function(){return{restrict:"A",scope:{fn:"=customValidator"},require:"ngModel",link:function(e,n,i,o){function t(n){var i=e.fn(n);return angular.isArray(i)?o.$setValidity.apply(o,_toConsumableArray(i)):o.$setValidity("custom",i),n}angular.isFunction(e.fn)&&o.$parsers.push(t)}}})}(),function(){angular.module("xos.uiComponents").component("xosAlert",{restrict:"E",bindings:{config:"=",show:"=?"},template:'\n <div ng-cloak class="alert alert-{{vm.config.type}}" ng-hide="!vm.show">\n <button type="button" class="close" ng-if="vm.config.closeBtn" ng-click="vm.dismiss()">\n <span aria-hidden="true">×</span>\n </button>\n <p ng-transclude></p>\n </div>\n ',transclude:!0,bindToController:!0,controllerAs:"vm",controller:["$timeout",function(e){var n=this;if(!this.config)throw new Error('[xosAlert] Please provide a configuration via the "config" attribute');this.show=this.show!==!1,this.dismiss=function(){n.show=!1},this.config.autoHide&&!function(){var i=e(function(){n.dismiss(),e.cancel(i)},n.config.autoHide)}()}]})}(),function(){function e(){var e=function(e){return e.split("_").join(" ").trim()},n=function(e){return e.split(/(?=[A-Z])/).map(function(e){return e.toLowerCase()}).join(" ")},i=function(e){return e.slice(0,1).toUpperCase()+e.slice(1)},o=function(o){return o=e(o),o=n(o),o=i(o).replace(/\s\s+/g," ")+":",o.replace("::",":")};return{_formatByUnderscore:e,_formatByUppercase:n,_capitalize:i,format:o}}angular.module("xos.uiComponents").factory("LabelFormatter",e)}();var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};!function(){angular.module("xos.uiComponents").service("XosFormHelpers",["_","LabelFormatter",function(e,n){var i=this;this._isEmail=function(e){var n=/(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;return n.test(e)},this._getFieldFormat=function(e){return angular.isArray(e)?"array":angular.isDate(e)||!Number.isNaN(Date.parse(e))&&/^\d+-\d+-\d+\D\d+:\d+:\d+\.\d+\D/.test(e)?"date":"boolean"==typeof e?"boolean":i._isEmail(e)?"email":angular.isString(e)||null===e?"text":"undefined"==typeof e?"undefined":_typeof(e)},this.buildFormStructure=function(o,t,r,a){var s={};return o=angular.extend(o,t),t=t||{},a&&e.each(a,function(e){s[e]={}}),e.each(Object.keys(o),function(e){s[e]={label:t[e]&&t[e].label?t[e].label+":":n.format(e),type:t[e]&&t[e].type?t[e].type:i._getFieldFormat(r[e]),validators:t[e]&&t[e].validators?t[e].validators:{},hint:t[e]&&t[e].hint?t[e].hint:""},t[e]&&t[e].options&&(s[e].options=t[e].options),t[e]&&t[e].properties&&(s[e].properties=t[e].properties),"date"===s[e].type&&(r[e]=new Date(r[e])),"number"===s[e].type&&(r[e]=parseInt(r[e],10))}),s},this.parseModelField=function(n){return e.reduce(n,function(e,n){return e[n]={},e},{})}}])}(),function(){function e(e){return function(n,i){if(angular.isUndefined(n))return!1;if(null===n||null===i)return n===i;if(angular.isObject(i)||angular.isObject(n))return angular.equals(i,n);if(e.isBoolean(n)||e.isBoolean(i))return 0!==n&&1!==n||(n=!!n),angular.equals(i,n);if(!angular.isString(n)||!angular.isString(i)){if(!angular.isDefined(n.toString)||!angular.isDefined(i.toString))return n===i;n=n.toString(),i=i.toString()}return n=n.toLowerCase()+"",i=i.toLowerCase()+"",n.indexOf(i)!==-1}}e.$inject=["_"],angular.module("xos.uiComponents").factory("Comparator",e)}(),function(){function e(e,n,i){e.interceptors.push("SetCSRFToken"),i.defaults.stripTrailingSlashes=!1}e.$inject=["$httpProvider","$interpolateProvider","$resourceProvider"],angular.module("xos.helpers",["ngCookies","ngResource","ngAnimate","xos.uiComponents"]).config(e).factory("_",["$window",function(e){return e._}])}(),function(){angular.module("xos.helpers").service("vSG-Collection",["$resource",function(e){return e("/api/service/vsg/")}])}(),function(){angular.module("xos.helpers").service("vOLT-Collection",["$resource",function(e){return e("/api/tenant/cord/volt/:volt_id/",{volt_id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Login",["$resource",function(e){return e("/api/utility/login/")}]).service("Logout",["$resource",function(e){return e("/api/utility/logout/")}])}(),function(){angular.module("xos.helpers").service("Users",["$resource",function(e){return e("/api/core/users/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Truckroll",["$resource",function(e){return e("/api/tenant/truckroll/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Tenants",["$resource",function(e){return e("/api/core/tenants/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Subscribers",["$resource",function(e){return e("/api/tenant/cord/subscriber/:id/",{id:"@id"},{update:{method:"PUT"},"View-a-Subscriber-Features-Detail":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/"},"Read-Subscriber-uplink_speed":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uplink_speed/"},"Update-Subscriber-uplink_speed":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uplink_speed/"},"Read-Subscriber-downlink_speed":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/downlink_speed/"},"Update-Subscriber-downlink_speed":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/downlink_speed/"},"Read-Subscriber-cdn":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/cdn/"},"Update-Subscriber-cdn":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/cdn/"},"Read-Subscriber-uverse":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uverse/"},"Update-Subscriber-uverse":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uverse/"},"Read-Subscriber-status":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/status/"},"Update-Subscriber-status":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/status/"}})}])}(),function(){angular.module("xos.helpers").service("SlicesPlus",["$http","$q",function(e,n){this.query=function(i){var o=n.defer();return e.get("/api/utility/slicesplus/",{params:i}).then(function(e){o.resolve(e.data)})["catch"](function(e){o.reject(e.data)}),{$promise:o.promise}},this.get=function(i,o){var t=n.defer();return e.get("/api/utility/slicesplus/"+i,{params:o}).then(function(e){t.resolve(e.data)})["catch"](function(e){t.reject(e.data)}),{$promise:t.promise}}}])}(),function(){angular.module("xos.helpers").service("Slices",["$resource",function(e){return e("/api/core/slices/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Sites",["$resource",function(e){return e("/api/core/sites/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Services",["$resource",function(e){return e("/api/core/services/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("ONOS-Services-Collection",["$resource",function(e){return e("/api/service/onos/")}])}(),function(){angular.module("xos.helpers").service("ONOS-App-Collection",["$resource",function(e){return e("/api/tenant/onos/app/")}])}(),function(){angular.module("xos.helpers").service("Nodes",["$resource",function(e){return e("/api/core/nodes/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Networkstemplates",["$resource",function(e){return e("/api/core/networktemplates/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Networks",["$resource",function(e){return e("/api/core/networks/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Me",["$q","$http",function(e,n){this.get=function(){var i=e.defer();return n.get("/api/utility/me/").then(function(e){i.resolve(e.data)})["catch"](function(e){i.reject(e)}),i.promise}}])}(),function(){angular.module("xos.helpers").service("Instances",["$resource",function(e){return e("/api/core/instances/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Images",["$resource",function(e){return e("/api/core/images/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Flavors",["$resource",function(e){return e("/api/core/flavors/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Example-Services-Collection",["$resource",function(e){return e("/api/service/exampleservice/")}])}(),function(){angular.module("xos.helpers").service("Deployments",["$resource",function(e){return e("/api/core/deployments/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Dashboards",["$resource","$q","$http",function(e,n,i){var o=e("/api/core/dashboardviews/:id/",{id:"@id"},{update:{method:"PUT"}});return o.prototype.$save=function(){var e=n.defer();return i.put("/api/core/dashboardviews/"+this.id+"/",this).then(function(n){e.resolve(n.data)})["catch"](function(n){e.reject(n.data)}),e.promise},o}])}(),function(){angular.module("xos.helpers").service("XosUserPrefs",["$cookies","Me","$q",function(e,n,i){var o=this,t=e.get("xosUserPrefs")?angular.fromJson(e.get("xosUserPrefs")):{};this.getAll=function(){return t=e.get("xosUserPrefs")?angular.fromJson(e.get("xosUserPrefs")):{}},this.setAll=function(n){e.put("xosUserPrefs",angular.toJson(n))},this.getSynchronizerNotificationStatus=function(){var e=!(arguments.length<=0||void 0===arguments[0])&&arguments[0];return e?o.getAll().synchronizers.notification[e]:o.getAll().synchronizers.notification},this.getUserDetailsCookie=function(){
+"use strict";function _toConsumableArray(e){if(Array.isArray(e)){for(var n=0,i=Array(e.length);n<e.length;n++)i[n]=e[n];return i}return Array.from(e)}!function(){angular.module("xos.uiComponents",["chart.js","RecursionHelper","dndLists"])}(),function(){angular.module("xos.uiComponents").component("xosSmartTable",{restrict:"E",bindings:{config:"="},template:'\n <div class="row" ng-show="vm.data.length > 0">\n <div class="col-xs-12 text-right">\n <a href="" class="btn btn-success" ng-click="vm.createItem()">\n Add\n </a>\n </div>\n </div>\n <div class="row">\n <div class="col-xs-12 table-responsive">\n <xos-table config="vm.tableConfig" data="vm.data"></xos-table>\n </div>\n </div>\n <div class="panel panel-default" ng-show="vm.detailedItem">\n <div class="panel-heading">\n <div class="row">\n <div class="col-xs-11">\n <h3 class="panel-title" ng-show="vm.detailedItem.id">Update {{vm.config.resource}} {{vm.detailedItem.id}}</h3>\n <h3 class="panel-title" ng-show="!vm.detailedItem.id">Create {{vm.config.resource}} item</h3>\n </div>\n <div class="col-xs-1">\n <a href="" ng-click="vm.cleanForm()">\n <i class="glyphicon glyphicon-remove pull-right"></i>\n </a>\n </div>\n </div>\n </div>\n <div class="panel-body">\n <xos-form config="vm.formConfig" ng-model="vm.detailedItem"></xos-form>\n </div>\n </div>\n <xos-alert config="{type: \'success\', closeBtn: true}" show="vm.responseMsg">{{vm.responseMsg}}</xos-alert>\n <xos-alert config="{type: \'danger\', closeBtn: true}" show="vm.responseErr">{{vm.responseErr}}</xos-alert>\n ',bindToController:!0,controllerAs:"vm",controller:["$injector","LabelFormatter","_","XosFormHelpers",function(e,n,i,o){var t=this;this.responseMsg=!1,this.responseErr=!1,this.tableConfig={columns:[],actions:[{label:"delete",icon:"remove",cb:function(e){t.Resource["delete"]({id:e.id}).$promise.then(function(){i.remove(t.data,function(n){return n.id===e.id}),t.responseMsg=t.config.resource+" with id "+e.id+" successfully deleted"})["catch"](function(n){t.responseErr=n.data.detail||"Error while deleting "+t.config.resource+" with id "+e.id})},color:"red"},{label:"details",icon:"search",cb:function(e){t.detailedItem=e}}],classes:"table table-striped table-bordered table-responsive",filter:"field",order:!0,pagination:{pageSize:10}},this.formConfig={exclude:this.config.hiddenFields,fields:{},formName:this.config.resource+"Form",actions:[{label:"Save",icon:"ok",cb:function(e){var n=void 0,i=!0;e.id?(n=e.$update(),i=!1):n=e.$save(),n.then(function(n){i&&t.data.push(angular.copy(n)),delete t.detailedItem,t.responseMsg=t.config.resource+" with id "+e.id+" successfully saved"})["catch"](function(n){t.responseErr=n.data.detail||"Error while saving "+t.config.resource+" with id "+e.id})},"class":"success"}]},this.cleanForm=function(){delete t.detailedItem},this.createItem=function(){t.detailedItem=new t.Resource},this.Resource=e.get(this.config.resource);var r=function(){t.Resource.query().$promise.then(function(e){if(!e[0])return void(t.data=e);var r=e[0],a=Object.keys(r);i.remove(a,function(e){return"id"===e||"validators"===e}),angular.isArray(t.config.hiddenFields)&&(a=i.difference(a,t.config.hiddenFields)),a.forEach(function(e){var i={label:n.format(e),prop:e};i.type=o._getFieldFormat(r[e]),t.tableConfig.columns.push(i)}),a.forEach(function(e){t.formConfig.fields[e]={label:n.format(e).replace(":",""),type:o._getFieldFormat(r[e])}}),t.data=e})};r()}]})}(),function(){angular.module("xos.uiComponents").component("xosSmartPie",{restrict:"E",bindings:{config:"="},template:'\n <canvas\n class="chart chart-pie {{vm.config.classes}}"\n chart-data="vm.data" chart-labels="vm.labels"\n chart-legend="{{vm.config.legend}}">\n </canvas>\n ',bindToController:!0,controllerAs:"vm",controller:["$injector","$interval","$scope","$timeout","_",function(e,n,i,o,t){var r=this;if(!this.config.resource&&!this.config.data)throw new Error("[xosSmartPie] Please provide a resource or an array of data in the configuration");var a=function(e){return t.groupBy(e,r.config.groupBy)},s=function(e){return t.reduce(Object.keys(e),function(n,i){return n.concat(e[i].length)},[])},l=function(e){return angular.isFunction(r.config.labelFormatter)?r.config.labelFormatter(Object.keys(e)):Object.keys(e)},c=function(e){var n=a(e);r.data=s(n),r.labels=l(n)};this.config.resource?!function(){r.Resource=e.get(r.config.resource);var i=function(){r.Resource.query().$promise.then(function(e){e[0]&&c(e)})};i(),r.config.poll&&n(function(){i()},1e3*r.config.poll)}():i.$watch(function(){return r.config.data},function(e){e&&c(r.config.data)},!0),i.$on("create",function(e,n){console.log("create: "+n.id)}),i.$on("destroy",function(e,n){console.log("destroy: "+n.id)})}]})}(),function(){angular.module("xos.uiComponents").component("xosValidation",{restrict:"E",bindings:{field:"=",form:"="},template:'\n <div ng-cloak>\n <xos-alert config="vm.config" show="vm.field.$error.required !== undefined && vm.field.$error.required !== false && (vm.field.$touched || vm.form.$submitted)">\n Field required\n </xos-alert>\n <xos-alert config="vm.config" show="vm.field.$error.email !== undefined && vm.field.$error.email !== false && (vm.field.$touched || vm.form.$submitted)">\n This is not a valid email\n </xos-alert>\n <xos-alert config="vm.config" show="vm.field.$error.minlength !== undefined && vm.field.$error.minlength !== false && (vm.field.$touched || vm.form.$submitted)">\n Too short\n </xos-alert>\n <xos-alert config="vm.config" show="vm.field.$error.maxlength !== undefined && vm.field.$error.maxlength !== false && (vm.field.$touched || vm.form.$submitted)">\n Too long\n </xos-alert>\n <xos-alert config="vm.config" show="vm.field.$error.custom !== undefined && vm.field.$error.custom !== false && (vm.field.$touched || vm.form.$submitted)">\n Field invalid\n </xos-alert>\n </div>\n ',transclude:!0,bindToController:!0,controllerAs:"vm",controller:function(){this.config={type:"danger"}}})}(),function(){angular.module("xos.uiComponents").component("xosTable",{restrict:"E",bindings:{data:"=",config:"="},template:'\n <div ng-show="vm.data.length > 0 && vm.loader == false">\n <div class="row" ng-if="vm.config.filter == \'fulltext\'">\n <div class="col-xs-12">\n <input\n class="form-control"\n placeholder="Type to search.."\n type="text"\n ng-model="vm.query"/>\n </div>\n </div>\n <table ng-class="vm.classes" ng-hide="vm.data.length == 0">\n <thead>\n <tr>\n <th ng-repeat="col in vm.columns">\n {{col.label}}\n <span ng-if="vm.config.order">\n <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = false">\n <i class="glyphicon glyphicon-chevron-up"></i>\n </a>\n <a href="" ng-click="vm.orderBy = col.prop; vm.reverse = true">\n <i class="glyphicon glyphicon-chevron-down"></i>\n </a>\n </span>\n </th>\n <th ng-if="vm.config.actions">Actions:</th>\n </tr>\n </thead>\n <tbody ng-if="vm.config.filter == \'field\'">\n <tr>\n <td ng-repeat="col in vm.columns">\n <input\n ng-if="col.type !== \'boolean\' && col.type !== \'array\' && col.type !== \'object\' && col.type !== \'custom\'"\n class="form-control"\n placeholder="Type to search by {{col.label}}"\n type="text"\n ng-model="vm.query[col.prop]"/>\n <select\n ng-if="col.type === \'boolean\'"\n class="form-control"\n ng-model="vm.query[col.prop]">\n <option value="">-</option>\n <option value="true">True</option>\n <option value="false">False</option>\n </select>\n </td>\n <td ng-if="vm.config.actions"></td>\n </tr>\n </tbody>\n <tbody>\n <tr ng-repeat="item in vm.data | filter:vm.query:vm.comparator | orderBy:vm.orderBy:vm.reverse | pagination:vm.currentPage * vm.config.pagination.pageSize | limitTo: (vm.config.pagination.pageSize || vm.data.length) track by $index">\n <td ng-repeat="col in vm.columns" xos-link-wrapper>\n <span ng-if="!col.type || col.type === \'text\'">{{item[col.prop]}}</span>\n <span ng-if="col.type === \'boolean\'">\n <i class="glyphicon"\n ng-class="{\'glyphicon-ok\': item[col.prop], \'glyphicon-remove\': !item[col.prop]}">\n </i>\n </span>\n <span ng-if="col.type === \'date\'">\n {{item[col.prop] | date:\'H:mm MMM d, yyyy\'}}\n </span>\n <span ng-if="col.type === \'array\'">\n {{item[col.prop] | arrayToList}}\n </span>\n <span ng-if="col.type === \'object\'">\n <dl class="dl-horizontal">\n <span ng-repeat="(k,v) in item[col.prop]">\n <dt>{{k}}</dt>\n <dd>{{v}}</dd>\n </span>\n </dl>\n </span>\n <span ng-if="col.type === \'custom\'">\n {{col.formatter(item)}}\n </span>\n <span ng-if="col.type === \'icon\'">\n <i class="glyphicon glyphicon-{{col.formatter(item)}}">\n </i>\n </span>\n </td>\n <td ng-if="vm.config.actions">\n <a href=""\n ng-repeat="action in vm.config.actions"\n ng-click="action.cb(item)"\n title="{{action.label}}">\n <i\n class="glyphicon glyphicon-{{action.icon}}"\n style="color: {{action.color}};"></i>\n </a>\n </td>\n </tr>\n </tbody>\n </table>\n <xos-pagination\n ng-if="vm.config.pagination"\n page-size="vm.config.pagination.pageSize"\n total-elements="vm.data.length"\n change="vm.goToPage">\n </xos-pagination>\n </div>\n <div ng-show="(vm.data.length == 0 || !vm.data) && vm.loader == false">\n <xos-alert config="{type: \'info\'}">\n No data to show.\n </xos-alert>\n </div>\n <div ng-show="vm.loader == true">\n <div class="loader"></div>\n </div>\n ',bindToController:!0,controllerAs:"vm",controller:["_","$scope","Comparator",function(e,n,i){var o=this;if(this.comparator=i,this.loader=!0,n.$watch(function(){return o.data},function(e){angular.isDefined(e)&&(o.loader=!1)}),!this.config)throw new Error('[xosTable] Please provide a configuration via the "config" attribute');if(!this.config.columns)throw new Error("[xosTable] Please provide a columns list in the configuration");this.config.order&&angular.isObject(this.config.order)&&(this.reverse=this.config.order.reverse||!1,this.orderBy=this.config.order.field||"id");var t=e.filter(this.config.columns,{type:"custom"});angular.isArray(t)&&t.length>0&&e.forEach(t,function(e){if(!e.formatter||!angular.isFunction(e.formatter))throw new Error("[xosTable] You have provided a custom field type, a formatter function should provided too.")});var r=e.filter(this.config.columns,{type:"icon"});angular.isArray(r)&&r.length>0&&e.forEach(r,function(e){if(!e.formatter||!angular.isFunction(e.formatter))throw new Error("[xosTable] You have provided an icon field type, a formatter function should provided too.")});var a=e.filter(this.config.columns,function(e){return angular.isDefined(e.link)});angular.isArray(a)&&a.length>0&&e.forEach(a,function(e){if(!angular.isFunction(e.link))throw new Error("[xosTable] The link property should be a function.")}),this.columns=this.config.columns,this.classes=this.config.classes||"table table-striped table-bordered",this.config.actions,this.config.pagination&&(this.currentPage=0,this.goToPage=function(e){o.currentPage=e})}]}).filter("arrayToList",function(){return function(e){return angular.isArray(e)?e.join(", "):e}}).directive("xosLinkWrapper",function(){return{restrict:"A",transclude:!0,template:'\n <a ng-if="col.link" href="{{col.link(item)}}">\n <div ng-transclude></div>\n </a>\n <div ng-transclude ng-if="!col.link"></div>\n '}})}(),function(){angular.module("xos.uiComponents").component("xosPagination",{restrict:"E",bindings:{pageSize:"=",totalElements:"=",change:"="},template:'\n <div class="row" ng-if="vm.pageList.length > 1">\n <div class="col-xs-12 text-center">\n <ul class="pagination">\n <li\n ng-click="vm.goToPage(vm.currentPage - 1)"\n ng-class="{disabled: vm.currentPage == 0}">\n <a href="" aria-label="Previous">\n <span aria-hidden="true">«</span>\n </a>\n </li>\n <li ng-repeat="i in vm.pageList" ng-class="{active: i === vm.currentPage}">\n <a href="" ng-click="vm.goToPage(i)">{{i + 1}}</a>\n </li>\n <li\n ng-click="vm.goToPage(vm.currentPage + 1)"\n ng-class="{disabled: vm.currentPage == vm.pages - 1}">\n <a href="" aria-label="Next">\n <span aria-hidden="true">»</span>\n </a>\n </li>\n </ul>\n </div>\n </div>\n ',bindToController:!0,controllerAs:"vm",controller:["$scope",function(e){var n=this;this.currentPage=0,this.goToPage=function(e){e<0||e===n.pages||(n.currentPage=e,n.change(e))},this.createPages=function(e){for(var n=[],i=0;i<e;i++)n.push(i);return n},e.$watch(function(){return n.totalElements},function(){n.totalElements&&(n.pages=Math.ceil(n.totalElements/n.pageSize),n.pageList=n.createPages(n.pages))})}]}).filter("pagination",function(){return function(e,n){return e&&angular.isArray(e)?(n=parseInt(n,10),e.slice(n)):e}})}(),function(){angular.module("xos.uiComponents").component("xosField",{restrict:"E",bindings:{name:"=",field:"=",ngModel:"="},template:'\n <label ng-if="vm.field.type !== \'object\' && vm.field.type !== \'array\'">{{vm.field.label}}</label>\n <input\n xos-custom-validator custom-validator="vm.field.validators.custom || null"\n ng-if="vm.field.type !== \'boolean\' && vm.field.type !== \'object\' && vm.field.type !== \'select\' && vm.field.type !== \'array\'"\n type="{{vm.field.type}}"\n name="{{vm.name}}"\n class="form-control"\n ng-model="vm.ngModel"\n ng-minlength="vm.field.validators.minlength || 0"\n ng-maxlength="vm.field.validators.maxlength || 2000"\n ng-required="vm.field.validators.required || false" />\n <select class="form-control" ng-if ="vm.field.type === \'select\'"\n name = "{{vm.name}}"\n ng-options="item.id as item.label for item in vm.field.options"\n ng-model="vm.ngModel"\n ng-required="vm.field.validators.required || false">\n </select>\n <span class="boolean-field" ng-if="vm.field.type === \'boolean\'">\n <a href="#"\n class="btn btn-success"\n ng-show="vm.ngModel"\n ng-click="vm.ngModel = false">\n <i class="glyphicon glyphicon-ok"></i>\n </a>\n <a href="#"\n class="btn btn-danger"\n ng-show="!vm.ngModel"\n ng-click="vm.ngModel = true">\n <i class="glyphicon glyphicon-remove"></i>\n </a>\n </span>\n <div\n class="panel panel-default object-field"\n ng-if="vm.field.type == \'object\' && (!vm.isEmptyObject(vm.ngModel) || !vm.isEmptyObject(vm.field.properties))"\n >\n <div class="panel-heading">{{vm.field.label}}</div>\n <div class="panel-body">\n <div ng-if="!vm.field.properties" ng-repeat="(k, v) in vm.ngModel">\n <xos-field\n name="k"\n field="{label: vm.formatLabel(k), type: vm.getType(v)}"\n ng-model="v">\n </xos-field>\n </div>\n <div ng-if="vm.field.properties" ng-repeat="(k, v) in vm.field.properties">\n <xos-field\n name="k"\n field="{\n label: v.label || vm.formatLabel(k),\n type: v.type,\n validators: v.validators\n }"\n ng-model="vm.ngModel[k]">\n </xos-field>\n </div>\n </div>\n </div>\n <div\n class="panel panel-default array-field"\n ng-if="vm.field.type == \'array\'">\n <div class="panel-heading">{{vm.field.label}}</div>\n <div class="panel-body selected">\n <ul class="draggable" dnd-list="vm.ngModel">\n <li\n class="array-element"\n ng-repeat="item in vm.ngModel"\n dnd-draggable="item"\n dnd-moved="vm.ngModel.splice($index, 1)"\n dnd-effect-allowed="move"\n dnd-selected="models.selected = item"\n >\n <div class="well well-sm text-center">\n {{item}}\n </div>\n </li>\n <div class="clearfix"></div>\n </ul>\n </div>\n <div class="panel-body unselected">\n <ul class="draggable" dnd-list="vm.field.availableOptions">\n <li\n class="array-element"\n ng-repeat="item in vm.field.availableOptions"\n dnd-draggable="item"\n dnd-moved="vm.field.availableOptions.splice($index, 1)"\n dnd-effect-allowed="move"\n dnd-selected="models.selected = item"\n >\n <div class="well well-sm text-center">\n {{item}}\n </div>\n </li>\n <div class="clearfix"></div>\n </ul>\n </div>\n </div>\n ',bindToController:!0,controllerAs:"vm",controller:["$attrs","$scope","XosFormHelpers","LabelFormatter","_",function(e,n,i,o,t){var r=this;if(!this.name)throw new Error("[xosField] Please provide a field name");if(!this.field)throw new Error("[xosField] Please provide a field definition");if(!this.field.type)throw new Error("[xosField] Please provide a type in the field definition");if(!e.ngModel)throw new Error("[xosField] Please provide an ng-model");this.getType=i._getFieldFormat,this.formatLabel=o.format,this.isEmptyObject=function(e){return!e||0===Object.keys(e).length},"array"===this.field.type&&n.$watch(function(){return r.ngModel.length},function(){r.field.availableOptions=t.difference(r.field.options,r.ngModel)})}]}).directive("xosCustomValidator",function(){return{restrict:"A",scope:{fn:"=customValidator"},require:"ngModel",link:function(e,n,i,o){function t(n){var i=e.fn(n);return angular.isArray(i)?o.$setValidity.apply(o,_toConsumableArray(i)):o.$setValidity("custom",i),n}angular.isFunction(e.fn)&&o.$parsers.push(t)}}})}(),function(){angular.module("xos.uiComponents").component("xosForm",{restrict:"E",bindings:{config:"=",ngModel:"="},template:'\n <form name="vm.{{vm.config.formName || \'form\'}}" novalidate>\n <div class="form-group" ng-repeat="(name, field) in vm.formField">\n <xos-field name="name" field="field" ng-model="vm.ngModel[name]"></xos-field>\n <xos-validation field="vm[vm.config.formName || \'form\'][name]" form = "vm[vm.config.formName || \'form\']"></xos-validation>\n <div class="alert alert-info" ng-show="(field.hint).length >0" role="alert">{{field.hint}}</div>\n </div>\n <div class="form-group" ng-if="vm.config.actions">\n <xos-alert config="vm.config.feedback" show="vm.config.feedback.show">{{vm.config.feedback.message}}</xos-alert>\n\n <button role="button" href=""\n ng-repeat="action in vm.config.actions"\n ng-click="action.cb(vm.ngModel, vm[vm.config.formName || \'form\'])"\n class="btn btn-{{action.class}}"\n title="{{action.label}}">\n <i class="glyphicon glyphicon-{{action.icon}}"></i>\n {{action.label}}\n </button>\n </div>\n </form>\n ',bindToController:!0,controllerAs:"vm",controller:["$scope","$log","_","XosFormHelpers",function(e,n,i,o){var t=this;if(!this.config)throw new Error('[xosForm] Please provide a configuration via the "config" attribute');if(!this.config.actions)throw new Error("[xosForm] Please provide an action list in the configuration");this.config.feedback||(this.config.feedback={show:!1,message:"Form submitted successfully !!!",type:"success"}),this.excludedField=["id","validators","created","updated","deleted","backend_status"],this.config&&this.config.exclude&&(this.excludedField=this.excludedField.concat(this.config.exclude)),this.formField=[],e.$watch(function(){return t.config},function(){if(t.ngModel){var e=i.difference(Object.keys(t.ngModel),t.excludedField),n=o.parseModelField(e);t.formField=o.buildFormStructure(n,t.config.fields,t.ngModel,t.config.order)}},!0),e.$watch(function(){return t.ngModel},function(e){if(t.formField={},e){var n=i.difference(Object.keys(e),t.excludedField),r=o.parseModelField(n);t.formField=o.buildFormStructure(r,t.config.fields,e,t.config.order)}})}]})}(),function(){angular.module("xos.uiComponents").component("xosAlert",{restrict:"E",bindings:{config:"=",show:"=?"},template:'\n <div ng-cloak class="alert alert-{{vm.config.type}}" ng-hide="!vm.show">\n <button type="button" class="close" ng-if="vm.config.closeBtn" ng-click="vm.dismiss()">\n <span aria-hidden="true">×</span>\n </button>\n <p ng-transclude></p>\n </div>\n ',transclude:!0,bindToController:!0,controllerAs:"vm",controller:["$timeout",function(e){var n=this;if(!this.config)throw new Error('[xosAlert] Please provide a configuration via the "config" attribute');this.show=this.show!==!1,this.dismiss=function(){n.show=!1},this.config.autoHide&&!function(){var i=e(function(){n.dismiss(),e.cancel(i)},n.config.autoHide)}()}]})}(),function(){function e(){var e=function(e){return e.split("_").join(" ").trim()},n=function(e){return e.split(/(?=[A-Z])/).map(function(e){return e.toLowerCase()}).join(" ")},i=function(e){return e.slice(0,1).toUpperCase()+e.slice(1)},o=function(o){return o=e(o),o=n(o),o=i(o).replace(/\s\s+/g," ")+":",o.replace("::",":")};return{_formatByUnderscore:e,_formatByUppercase:n,_capitalize:i,format:o}}angular.module("xos.uiComponents").factory("LabelFormatter",e)}();var _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};!function(){angular.module("xos.uiComponents").service("XosFormHelpers",["_","LabelFormatter",function(e,n){var i=this;this._isEmail=function(e){var n=/(([^<>()[\]\\.,;:\s@\"]+(\.[^<>()[\]\\.,;:\s@\"]+)*)|(\".+\"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/;return n.test(e)},this._getFieldFormat=function(e){return angular.isArray(e)?"array":angular.isDate(e)||!Number.isNaN(Date.parse(e))&&/^\d+-\d+-\d+\D\d+:\d+:\d+\.\d+\D/.test(e)?"date":"boolean"==typeof e?"boolean":i._isEmail(e)?"email":angular.isString(e)||null===e?"text":"undefined"==typeof e?"undefined":_typeof(e)},this.buildFormStructure=function(o,t,r,a){var s={};return o=angular.extend(o,t),t=t||{},a&&e.each(a,function(e){s[e]={}}),e.each(Object.keys(o),function(e){s[e]={label:t[e]&&t[e].label?t[e].label+":":n.format(e),type:t[e]&&t[e].type?t[e].type:i._getFieldFormat(r[e]),validators:t[e]&&t[e].validators?t[e].validators:{},hint:t[e]&&t[e].hint?t[e].hint:""},t[e]&&t[e].options&&(s[e].options=t[e].options),t[e]&&t[e].properties&&(s[e].properties=t[e].properties),"date"===s[e].type&&(r[e]=new Date(r[e])),"number"===s[e].type&&(r[e]=parseInt(r[e],10))}),s},this.parseModelField=function(n){return e.reduce(n,function(e,n){return e[n]={},e},{})}}])}(),function(){function e(e){return function(n,i){if(angular.isUndefined(n))return!1;if(null===n||null===i)return n===i;if(angular.isObject(i)||angular.isObject(n))return angular.equals(i,n);if(e.isBoolean(n)||e.isBoolean(i))return 0!==n&&1!==n||(n=!!n),angular.equals(i,n);if(!angular.isString(n)||!angular.isString(i)){if(!angular.isDefined(n.toString)||!angular.isDefined(i.toString))return n===i;n=n.toString(),i=i.toString()}return n=n.toLowerCase()+"",i=i.toLowerCase()+"",n.indexOf(i)!==-1}}e.$inject=["_"],angular.module("xos.uiComponents").factory("Comparator",e)}(),function(){function e(e,n,i){e.interceptors.push("SetCSRFToken"),i.defaults.stripTrailingSlashes=!1}e.$inject=["$httpProvider","$interpolateProvider","$resourceProvider"],angular.module("xos.helpers",["ngCookies","ngResource","ngAnimate","xos.uiComponents"]).config(e).factory("_",["$window",function(e){return e._}])}(),function(){angular.module("xos.helpers").service("vSG-Collection",["$resource",function(e){return e("/api/service/vsg/")}])}(),function(){angular.module("xos.helpers").service("vOLT-Collection",["$resource",function(e){return e("/api/tenant/cord/volt/:volt_id/",{volt_id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Login",["$resource",function(e){return e("/api/utility/login/")}]).service("Logout",["$resource",function(e){return e("/api/utility/logout/")}])}(),function(){angular.module("xos.helpers").service("Users",["$resource",function(e){return e("/api/core/users/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Truckroll",["$resource",function(e){return e("/api/tenant/truckroll/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Tenants",["$resource",function(e){return e("/api/core/tenants/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Subscribers",["$resource",function(e){return e("/api/tenant/cord/subscriber/:id/",{id:"@id"},{update:{method:"PUT"},"View-a-Subscriber-Features-Detail":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/"},"Read-Subscriber-uplink_speed":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uplink_speed/"},"Update-Subscriber-uplink_speed":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uplink_speed/"},"Read-Subscriber-downlink_speed":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/downlink_speed/"},"Update-Subscriber-downlink_speed":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/downlink_speed/"},"Read-Subscriber-cdn":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/cdn/"},"Update-Subscriber-cdn":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/cdn/"},"Read-Subscriber-uverse":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uverse/"},"Update-Subscriber-uverse":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/uverse/"},"Read-Subscriber-status":{method:"GET",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/status/"},"Update-Subscriber-status":{method:"PUT",isArray:!1,url:"/api/tenant/cord/subscriber/:id/features/status/"}})}])}(),function(){angular.module("xos.helpers").service("SlicesPlus",["$http","$q",function(e,n){this.query=function(i){var o=n.defer();return e.get("/api/utility/slicesplus/",{params:i}).then(function(e){o.resolve(e.data)})["catch"](function(e){o.reject(e.data)}),{$promise:o.promise}},this.get=function(i,o){var t=n.defer();return e.get("/api/utility/slicesplus/"+i,{params:o}).then(function(e){t.resolve(e.data)})["catch"](function(e){t.reject(e.data)}),{$promise:t.promise}}}])}(),function(){angular.module("xos.helpers").service("Slices",["$resource",function(e){return e("/api/core/slices/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Sites",["$resource",function(e){return e("/api/core/sites/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Services",["$resource",function(e){return e("/api/core/services/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("ONOS-Services-Collection",["$resource",function(e){return e("/api/service/onos/")}])}(),function(){angular.module("xos.helpers").service("ONOS-App-Collection",["$resource",function(e){return e("/api/tenant/onos/app/")}])}(),function(){angular.module("xos.helpers").service("Nodes",["$resource",function(e){return e("/api/core/nodes/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Networkstemplates",["$resource",function(e){return e("/api/core/networktemplates/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Networks",["$resource",function(e){return e("/api/core/networks/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Me",["$q","$http",function(e,n){this.get=function(){var i=e.defer();return n.get("/api/utility/me/").then(function(e){i.resolve(e.data)})["catch"](function(e){i.reject(e)}),i.promise}}])}(),function(){angular.module("xos.helpers").service("Instances",["$resource",function(e){return e("/api/core/instances/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Images",["$resource",function(e){return e("/api/core/images/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Flavors",["$resource",function(e){return e("/api/core/flavors/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Example-Services-Collection",["$resource",function(e){return e("/api/service/exampleservice/")}])}(),function(){angular.module("xos.helpers").service("Deployments",["$resource",function(e){return e("/api/core/deployments/:id/",{id:"@id"},{update:{method:"PUT"}})}])}(),function(){angular.module("xos.helpers").service("Dashboards",["$resource","$q","$http",function(e,n,i){var o=e("/api/core/dashboardviews/:id/",{id:"@id"},{update:{method:"PUT"}});return o.prototype.$save=function(){var e=n.defer();return i.put("/api/core/dashboardviews/"+this.id+"/",this).then(function(n){e.resolve(n.data)})["catch"](function(n){e.reject(n.data)}),e.promise},o}])}(),function(){angular.module("xos.helpers").service("XosUserPrefs",["$cookies","Me","$q",function(e,n,i){var o=this,t=e.get("xosUserPrefs")?angular.fromJson(e.get("xosUserPrefs")):{};this.getAll=function(){return t=e.get("xosUserPrefs")?angular.fromJson(e.get("xosUserPrefs")):{}},this.setAll=function(n){e.put("xosUserPrefs",angular.toJson(n))},this.getSynchronizerNotificationStatus=function(){var e=!(arguments.length<=0||void 0===arguments[0])&&arguments[0];return e?o.getAll().synchronizers.notification[e]:o.getAll().synchronizers.notification},this.getUserDetailsCookie=function(){
var e=i.defer(),n=o.getAll();return n.userData?e.resolve(n.userData):o.setUserDetailsCookie().$promise.then(function(n){e.resolve(n)}),{$promise:e.promise}},this.setUserDetailsCookie=function(){var e=arguments.length<=0||void 0===arguments[0]?null:arguments[0],t=i.defer(),r=o.getAll();return e?(r.userData=e,o.setAll(r),t.resolve(e)):n.get().then(function(e){r.userData=e,o.setAll(r),t.resolve(e)})["catch"](function(e){t.reject(e)}),{$promise:t.promise}},this.setSynchronizerNotificationStatus=function(){var e=!(arguments.length<=0||void 0===arguments[0])&&arguments[0],n=arguments[1];if(!e)throw new Error("[XosUserPrefs] When updating a synchronizer is mandatory to provide a name.");var i=o.getAll();i.synchronizers||(i.synchronizers={notification:{}}),i.synchronizers.notification[e]=n,o.setAll(i)}}])}(),function(){angular.module("xos.helpers").service("GraphService",["$q","Tenants","Services",function(e,n,i){var o=this;this.loadCoarseData=function(){var o=void 0,t=e.defer();return i.query().$promise.then(function(e){return o=e,n.query({kind:"coarse"}).$promise}).then(function(e){t.resolve({tenants:e,services:o})}),t.promise},this.getCoarseGraph=function(){return o.loadCoarseData().then(function(e){console.log(e)}),"ciao"}}])}(),function(){angular.module("xos.helpers").factory("Notification",function(){return window.Notification}).service("xosNotification",["$q","$log","Notification",function(e,n,i){var o=this;this.checkPermission=function(){var n=e.defer();return i.requestPermission().then(function(e){"granted"===e?n.resolve(e):n.reject(e)}),n.promise},this.sendNotification=function(e,o){var t=new i(e,o);t.onerror=function(e){n.error(e)}},this.notify=function(e,t){"Notification"in window?"granted"!==i.permission?o.checkPermission().then(function(){return o.sendNotification(e,t)}):"granted"===i.permission&&o.sendNotification(e,t):n.info("This browser does not support desktop notification")}}])}(),function(){function e(){return{request:function(e){return e.url.indexOf(".html")===-1&&(e.url+="?no_hyperlinks=1"),e}}}angular.module("xos.helpers").factory("NoHyperlinks",e)}(),angular.module("xos.helpers").config(["$provide",function(e){e.decorator("$log",["$delegate",function(e){var n=function(){return window.location.href.indexOf("debug=true")>=0},i=e.log,o=e.info,t=e.warn,r=e.debug,a=function(i){return function(){if(n()){var o=[].slice.call(arguments),t=new Date;return o[0]="["+t.getHours()+":"+t.getMinutes()+":"+t.getSeconds()+"] "+o[0],!angular.isFunction(e.reset)||e.debug.logs instanceof Array||e.reset(),i.apply(null,o)}}};return e.info=a(o),e.log=a(i),e.warn=a(t),e.debug=a(r),e}])}]),function(){function e(e){return{request:function(n){return"GET"!==n.method&&(n.headers["X-CSRFToken"]=e.get("xoscsrftoken")),n}}}e.$inject=["$cookies"],angular.module("xos.helpers").factory("SetCSRFToken",e)}();
\ No newline at end of file
diff --git a/dist/xosUiComponents.js b/dist/xosUiComponents.js
index 0384480..2392930 100644
--- a/dist/xosUiComponents.js
+++ b/dist/xosUiComponents.js
@@ -28,8 +28,6 @@
angular.module('xos.uiComponents', ['chart.js', 'RecursionHelper', 'dndLists']);
})();
-//# sourceMappingURL=../maps/ui_components/ui-components.module.js.map
-
'use strict';
/**
@@ -249,8 +247,6 @@
}]
});
})();
-//# sourceMappingURL=../../../maps/ui_components/smartComponents/smartTable/smartTable.component.js.map
-
'use strict';
/**
@@ -496,8 +492,6 @@
}]
});
})();
-//# sourceMappingURL=../../../maps/ui_components/smartComponents/smartPie/smartPie.component.js.map
-
'use strict';
/**
@@ -592,8 +586,6 @@
}
});
})();
-//# sourceMappingURL=../../../maps/ui_components/dumbComponents/validation/validation.component.js.map
-
'use strict';
/**
@@ -1024,8 +1016,6 @@
};
});
})();
-//# sourceMappingURL=../../../maps/ui_components/dumbComponents/table/table.component.js.map
-
'use strict';
/**
@@ -1051,6 +1041,7 @@
* ```
* {
* exclude: ['id', 'validators', 'created', 'updated', 'deleted'], //field to be skipped in the form, the provide values are concatenated
+ * order: ['field1', 'field2'], // ordering the fields (missing ones are attached at the end)
* actions: [ // define the form buttons with related callback
* {
label: 'save',
@@ -1085,6 +1076,7 @@
* }
* }
* ```
+ * @param {Object} ngModel The model object (it is mandatory to specify at least an empty object)
* @element ANY
* @scope
* @requires xos.uiComponents.directive:xosField
@@ -1136,21 +1128,20 @@
return $window._;
})
.controller('SampleCtrl1', function(SampleResource){
- this.model = {
- };
+ this.model = {};
this.config = {
exclude: ['password', 'last_login'],
formName: 'sampleForm1',
feedback: {
show: false,
- message: 'Form submitted successfully !!!',
+ message: 'Form submitted successfully!',
type: 'success'
},
actions: [
{
label: 'Save',
- icon: 'ok', // refers to bootstraps glyphicon
- cb: (user) => { // receive the model
+ icon: 'ok',
+ cb: (user) => {
console.log(user);
this.config.feedback.show = true;
this.config.feedback.type='success';
@@ -1158,6 +1149,7 @@
class: 'success'
}
],
+ order: ['site', 'last_name', 'first_name', 'age'],
fields: {
first_name: {
type: 'string',
@@ -1180,27 +1172,24 @@
min: 21
}
},
- site: {
- label: 'Site',
- type: 'select',
- validators: { required: true},
- hint: 'The Site this Slice belongs to',
- options: []
+ site: {
+ label: 'Site',
+ type: 'select',
+ validators: { required: true},
+ hint: 'The Site this Slice belongs to',
+ options: []
},
}
};
SampleResource.query().$promise
- .then((users) => {
- //this.users_site = users;
- //console.log(users);
+ .then((users) => {
this.optionVal = users;
this.config.fields['site'].options = this.optionVal;
- //= this.optionVal;
- })
- .catch((e) => {
- throw new Error(e);
+ })
+ .catch((e) => {
+ throw new Error(e);
+ });
});
- });
</file>
<file name="backend.js">
angular.module('sampleForm1')
@@ -1212,7 +1201,7 @@
.service('SampleResource', function($resource){
return $resource('/test/:id', {id: '@id'});
});
- </file>
+ </file>
<file name="index.html">
<div ng-controller="SampleCtrl1 as vm">
<xos-form ng-model="vm.model" config="vm.config"></xos-form>
@@ -1264,7 +1253,7 @@
}
var diff = _.difference(Object.keys(_this.ngModel), _this.excludedField);
var modelField = XosFormHelpers.parseModelField(diff);
- _this.formField = XosFormHelpers.buildFormStructure(modelField, _this.config.fields, _this.ngModel);
+ _this.formField = XosFormHelpers.buildFormStructure(modelField, _this.config.fields, _this.ngModel, _this.config.order);
}, true);
$scope.$watch(function () {
@@ -1282,8 +1271,6 @@
}]
});
})();
-//# sourceMappingURL=../../../maps/ui_components/dumbComponents/form/form.component.js.map
-
'use strict';
/**
@@ -1384,8 +1371,6 @@
};
});
})();
-//# sourceMappingURL=../../../maps/ui_components/dumbComponents/pagination/pagination.component.js.map
-
'use strict';
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
@@ -1472,14 +1457,25 @@
};
this.field5 = {
name: 'select',
- label: 'Select field:',
- type: 'select',
- model: 1,
- options: [
- {id: 1, label: 'One'},
- {id: 2, label: 'Two'},
- {id: 3, label: 'Three'},
- ]
+ field: {
+ label: 'Select field:',
+ type: 'select',
+ options: [
+ {id: 1, label: 'One'},
+ {id: 2, label: 'Two'},
+ {id: 3, label: 'Three'},
+ ]
+ },
+ model: 1
+ };
+ this.arrayField = {
+ name: 'array',
+ field: {
+ label: 'Array field:',
+ type: 'array',
+ options: ['one', 'two', 'three', 'four']
+ },
+ model: ['one', 'two'],
};
});
</file>
@@ -1490,6 +1486,7 @@
<xos-field ng-model="vm.field3.model" name="vm.field3.name" field="vm.field3.field"></xos-field>
<xos-field ng-model="vm.field4.model" name="vm.field4.name" field="vm.field4.field"></xos-field>
<xos-field ng-model="vm.field5.model" name="vm.field5.name" field="vm.field5.field"></xos-field>
+ <xos-field ng-model="vm.arrayField.model" name="vm.arrayField.name" field="vm.arrayField.field"></xos-field>
</div>
</file>
</example>
@@ -1619,8 +1616,6 @@
};
});
})();
-//# sourceMappingURL=../../../maps/ui_components/dumbComponents/field/field.component.js.map
-
'use strict';
/**
@@ -1756,8 +1751,6 @@
}]
});
})();
-//# sourceMappingURL=../../../maps/ui_components/dumbComponents/alert/alert.component.js.map
-
'use strict';
(function () {
@@ -1856,8 +1849,6 @@
};
}
})();
-//# sourceMappingURL=../../../maps/services/helpers/ui/label_formatter.service.js.map
-
'use strict';
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
@@ -1956,7 +1947,6 @@
**/
this.buildFormStructure = function (modelField, customField, model, order) {
-
var orderedForm = {};
modelField = angular.extend(modelField, customField);
@@ -2024,8 +2014,6 @@
};
}]);
})();
-//# sourceMappingURL=../../../maps/services/helpers/ui/form.helpers.js.map
-
'use strict';
(function () {
@@ -2122,8 +2110,6 @@
};
}
})();
-//# sourceMappingURL=../../../maps/services/helpers/ui/comparator.service.js.map
-
'use strict';
(function () {
@@ -2165,8 +2151,6 @@
$resourceProvider.defaults.stripTrailingSlashes = false;
}
})();
-//# sourceMappingURL=maps/xosHelpers.module.js.map
-
'use strict';
(function () {
@@ -2182,8 +2166,6 @@
return $resource('/api/service/vsg/');
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/vSG.js.map
-
'use strict';
(function () {
@@ -2201,8 +2183,6 @@
});
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/vOLT.js.map
-
'use strict';
(function () {
@@ -2226,8 +2206,6 @@
return $resource('/api/utility/logout/');
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/Utility.js.map
-
'use strict';
(function () {
@@ -2245,8 +2223,6 @@
});
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/Users.js.map
-
'use strict';
(function () {
@@ -2264,8 +2240,6 @@
});
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/Truckroll.js.map
-
'use strict';
(function () {
@@ -2283,8 +2257,6 @@
});
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/Tenant.js.map
-
'use strict';
(function () {
@@ -2434,8 +2406,6 @@
});
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/Subscribers.js.map
-
'use strict';
(function () {
@@ -2473,8 +2443,6 @@
};
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/Slices_plus.js.map
-
'use strict';
(function () {
@@ -2492,8 +2460,6 @@
});
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/Slices.js.map
-
'use strict';
(function () {
@@ -2511,8 +2477,6 @@
});
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/Sites.js.map
-
'use strict';
(function () {
@@ -2530,8 +2494,6 @@
});
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/Services.js.map
-
'use strict';
(function () {
@@ -2547,8 +2509,6 @@
return $resource('/api/service/onos/');
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/ONOS-Services.js.map
-
'use strict';
(function () {
@@ -2564,8 +2524,6 @@
return $resource('/api/tenant/onos/app/');
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/ONOS-Apps.js.map
-
'use strict';
(function () {
@@ -2583,8 +2541,6 @@
});
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/Nodes.js.map
-
'use strict';
(function () {
@@ -2602,8 +2558,6 @@
});
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/Networkstemplates.js.map
-
'use strict';
(function () {
@@ -2621,8 +2575,6 @@
});
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/Networks.js.map
-
'use strict';
(function () {
@@ -2648,8 +2600,6 @@
};
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/Me.js.map
-
'use strict';
(function () {
@@ -2667,8 +2617,6 @@
});
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/Instances.js.map
-
'use strict';
(function () {
@@ -2686,8 +2634,6 @@
});
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/Images.js.map
-
'use strict';
(function () {
@@ -2705,8 +2651,6 @@
});
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/Flavors.js.map
-
'use strict';
(function () {
@@ -2722,8 +2666,6 @@
return $resource('/api/service/exampleservice/');
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/Example.js.map
-
'use strict';
(function () {
@@ -2741,8 +2683,6 @@
});
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/Deployments.js.map
-
'use strict';
(function () {
@@ -2774,8 +2714,6 @@
return r;
}]);
})();
-//# sourceMappingURL=../../maps/services/rest/Dashboards.js.map
-
'use strict';
(function () {
@@ -2936,8 +2874,6 @@
};
}]);
})();
-//# sourceMappingURL=../../maps/services/helpers/user-prefs.service.js.map
-
'use strict';
(function () {
@@ -2979,8 +2915,6 @@
};
}]);
})();
-//# sourceMappingURL=../maps/services/service_graph.service.js.map
-
'use strict';
/* eslint-disable angular/ng_window_service*/
@@ -3040,8 +2974,6 @@
};
}]);
})();
-//# sourceMappingURL=../maps/services/notification.service.js.map
-
'use strict';
(function () {
@@ -3066,8 +2998,6 @@
};
}
})();
-//# sourceMappingURL=../maps/services/noHyperlinks.interceptor.js.map
-
'use strict';
// TODO write tests for log
@@ -3127,8 +3057,6 @@
return $delegate;
}]);
}]);
-//# sourceMappingURL=../maps/services/log.decorator.js.map
-
'use strict';
(function () {
@@ -3154,8 +3082,6 @@
};
}
})();
-//# sourceMappingURL=../maps/services/csrfToken.interceptor.js.map
-
/**
* @ngdoc overview
* @name ngXosLib
@@ -3169,5 +3095,4 @@
* ## Issues
* Please report issues at https://jira.opencord.org
**/
-"use strict";
-//# sourceMappingURL=maps/index.ngdoc.js.map
+"use strict";
\ No newline at end of file
diff --git a/src/services/helpers/ui/form.helpers.js b/src/services/helpers/ui/form.helpers.js
index 331cdb0..5dbecd7 100644
--- a/src/services/helpers/ui/form.helpers.js
+++ b/src/services/helpers/ui/form.helpers.js
@@ -94,7 +94,6 @@
**/
this.buildFormStructure = (modelField, customField, model, order) => {
-
const orderedForm = {};
modelField = angular.extend(modelField, customField);
diff --git a/src/ui_components/dumbComponents/field/field.component.js b/src/ui_components/dumbComponents/field/field.component.js
index 6fc07ac..6b413bb 100644
--- a/src/ui_components/dumbComponents/field/field.component.js
+++ b/src/ui_components/dumbComponents/field/field.component.js
@@ -85,14 +85,26 @@
this.field5 = {
name: 'select',
- label: 'Select field:',
- type: 'select',
- model: 1,
- options: [
- {id: 1, label: 'One'},
- {id: 2, label: 'Two'},
- {id: 3, label: 'Three'},
- ]
+ field: {
+ label: 'Select field:',
+ type: 'select',
+ options: [
+ {id: 1, label: 'One'},
+ {id: 2, label: 'Two'},
+ {id: 3, label: 'Three'},
+ ]
+ },
+ model: 1
+ };
+
+ this.arrayField = {
+ name: 'array',
+ field: {
+ label: 'Array field:',
+ type: 'array',
+ options: ['one', 'two', 'three', 'four']
+ },
+ model: ['one', 'two'],
};
});
</file>
@@ -103,6 +115,7 @@
<xos-field ng-model="vm.field3.model" name="vm.field3.name" field="vm.field3.field"></xos-field>
<xos-field ng-model="vm.field4.model" name="vm.field4.name" field="vm.field4.field"></xos-field>
<xos-field ng-model="vm.field5.model" name="vm.field5.name" field="vm.field5.field"></xos-field>
+ <xos-field ng-model="vm.arrayField.model" name="vm.arrayField.name" field="vm.arrayField.field"></xos-field>
</div>
</file>
</example>
diff --git a/src/ui_components/dumbComponents/form/form.component.js b/src/ui_components/dumbComponents/form/form.component.js
index ecdddc6..185abc3 100644
--- a/src/ui_components/dumbComponents/form/form.component.js
+++ b/src/ui_components/dumbComponents/form/form.component.js
@@ -22,6 +22,7 @@
* ```
* {
* exclude: ['id', 'validators', 'created', 'updated', 'deleted'], //field to be skipped in the form, the provide values are concatenated
+ * order: ['field1', 'field2'], // ordering the fields (missing ones are attached at the end)
* actions: [ // define the form buttons with related callback
* {
label: 'save',
@@ -56,6 +57,7 @@
* }
* }
* ```
+ * @param {Object} ngModel The model object (it is mandatory to specify at least an empty object)
* @element ANY
* @scope
* @requires xos.uiComponents.directive:xosField
@@ -112,23 +114,21 @@
})
.controller('SampleCtrl1', function(SampleResource){
-
- this.model = {
- };
+ this.model = {};
this.config = {
exclude: ['password', 'last_login'],
formName: 'sampleForm1',
feedback: {
show: false,
- message: 'Form submitted successfully !!!',
+ message: 'Form submitted successfully!',
type: 'success'
},
actions: [
{
label: 'Save',
- icon: 'ok', // refers to bootstraps glyphicon
- cb: (user) => { // receive the model
+ icon: 'ok',
+ cb: (user) => {
console.log(user);
this.config.feedback.show = true;
this.config.feedback.type='success';
@@ -136,6 +136,7 @@
class: 'success'
}
],
+ order: ['site', 'last_name', 'first_name', 'age'],
fields: {
first_name: {
type: 'string',
@@ -158,29 +159,23 @@
min: 21
}
},
-
site: {
- label: 'Site',
- type: 'select',
- validators: { required: true},
- hint: 'The Site this Slice belongs to',
- options: []
+ label: 'Site',
+ type: 'select',
+ validators: { required: true},
+ hint: 'The Site this Slice belongs to',
+ options: []
},
}
};
SampleResource.query().$promise
- .then((users) => {
- //this.users_site = users;
- //console.log(users);
+ .then((users) => {
this.optionVal = users;
this.config.fields['site'].options = this.optionVal;
- //= this.optionVal;
-
- })
- .catch((e) => {
- throw new Error(e);
- });
-
+ })
+ .catch((e) => {
+ throw new Error(e);
+ });
});
</file>
<file name="backend.js">
@@ -193,7 +188,6 @@
.service('SampleResource', function($resource){
return $resource('/test/:id', {id: '@id'});
});
-
</file>
<file name="index.html">
<div ng-controller="SampleCtrl1 as vm">
@@ -264,7 +258,7 @@
}
let diff = _.difference(Object.keys(this.ngModel), this.excludedField);
let modelField = XosFormHelpers.parseModelField(diff);
- this.formField = XosFormHelpers.buildFormStructure(modelField, this.config.fields, this.ngModel);
+ this.formField = XosFormHelpers.buildFormStructure(modelField, this.config.fields, this.ngModel, this.config.order);
}, true);
$scope.$watch(() => this.ngModel, (model) => {