blob: 3c9bf7e549555e9631eca202003b7c3e084cffd3 [file] [log] [blame]
Matteo Scandolo686547a2017-08-08 13:05:25 -07001
2/*
3 * Copyright 2017-present Open Networking Foundation
4
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8
9 * http://www.apache.org/licenses/LICENSE-2.0
10
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18
Matteo Scandoloa5d03d52016-07-21 11:35:46 -070019/**
20 * © OpenCORD
21 *
22 * Visit http://guide.xosproject.org/devguide/addview/ for more information
23 *
24 * Created by teone on 3/24/16.
25 */
26
27(function () {
28 'use strict';
29
30 angular.module('xos.uiComponents')
31
32 /**
33 * @ngdoc directive
34 * @name xos.uiComponents.directive:xosSmartTable
35 * @link xos.uiComponents.directive:xosTable xosTable
36 * @link xos.uiComponents.directive:xosForm xosForm
37 * @restrict E
38 * @description The xos-table directive
39 * @param {Object} config The configuration for the component,
40 * it is composed by the name of an angular [$resource](https://docs.angularjs.org/api/ngResource/service/$resource)
41 * and an array of fields that shouldn't be printed.
42 * ```
43 * {
44 resource: 'Users',
45 hiddenFields: []
46 }
47 * ```
48 * @scope
49 * @example
50
51 <example module="sampleSmartTable">
52 <file name="index.html">
53 <div ng-controller="SampleCtrl as vm">
54 <xos-smart-table config="vm.config"></xos-smart-table>
55 </div>
56 </file>
57 <file name="script.js">
58 angular.module('sampleSmartTable', ['xos.uiComponents', 'ngResource', 'ngMockE2E'])
59 // This is only for documentation purpose
60 .run(function($httpBackend, _){
61 let datas = [{id: 1, name: 'Jhon', surname: 'Doe'}];
62 let count = 1;
63
64 let paramsUrl = new RegExp(/\/test\/(.+)/);
65
66 $httpBackend.whenDELETE(paramsUrl, undefined, ['id']).respond((method, url, data, headers, params) => {
67 data = angular.fromJson(data);
68 let id = url.match(paramsUrl)[1];
69 _.remove(datas, (d) => {
70 return d.id === parseInt(id);
71 })
72 return [204];
73 });
74
75 $httpBackend.whenGET('/test').respond(200, datas)
76 $httpBackend.whenPOST('/test').respond((method, url, data) => {
77 data = angular.fromJson(data);
78 data.id = ++count;
79 datas.push(data);
80 return [201, data, {}];
81 });
82 })
83 .factory('_', function($window){
84 return $window._;
85 })
86 .service('SampleResource', function($resource){
87 return $resource('/test/:id', {id: '@id'});
88 })
89 // End of documentation purpose, example start
90 .controller('SampleCtrl', function(){
91 this.config = {
92 resource: 'SampleResource'
93 };
94 });
95 </file>
96 </example>
97 */
98
Matteo Scandolo1d689852016-09-29 09:42:12 -070099 .component('xosSmartTable', {
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700100 restrict: 'E',
Arpit Agarwal34b63832016-08-08 11:59:45 -0700101 bindings: {
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700102 config: '='
103 },
104 template: `
105 <div class="row" ng-show="vm.data.length > 0">
106 <div class="col-xs-12 text-right">
107 <a href="" class="btn btn-success" ng-click="vm.createItem()">
108 Add
109 </a>
110 </div>
111 </div>
112 <div class="row">
113 <div class="col-xs-12 table-responsive">
114 <xos-table config="vm.tableConfig" data="vm.data"></xos-table>
115 </div>
116 </div>
117 <div class="panel panel-default" ng-show="vm.detailedItem">
118 <div class="panel-heading">
119 <div class="row">
120 <div class="col-xs-11">
121 <h3 class="panel-title" ng-show="vm.detailedItem.id">Update {{vm.config.resource}} {{vm.detailedItem.id}}</h3>
122 <h3 class="panel-title" ng-show="!vm.detailedItem.id">Create {{vm.config.resource}} item</h3>
123 </div>
124 <div class="col-xs-1">
125 <a href="" ng-click="vm.cleanForm()">
126 <i class="glyphicon glyphicon-remove pull-right"></i>
127 </a>
128 </div>
129 </div>
130 </div>
131 <div class="panel-body">
132 <xos-form config="vm.formConfig" ng-model="vm.detailedItem"></xos-form>
133 </div>
134 </div>
135 <xos-alert config="{type: 'success', closeBtn: true}" show="vm.responseMsg">{{vm.responseMsg}}</xos-alert>
136 <xos-alert config="{type: 'danger', closeBtn: true}" show="vm.responseErr">{{vm.responseErr}}</xos-alert>
137 `,
138 bindToController: true,
139 controllerAs: 'vm',
140 controller: function($injector, LabelFormatter, _, XosFormHelpers){
Arpit Agarwal34b63832016-08-08 11:59:45 -0700141
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700142 // TODO
143 // - Validate the config (what if resource does not exist?)
144
145 // NOTE
146 // Corner case
147 // - if response is empty, how can we generate a form ?
148
149 this.responseMsg = false;
150 this.responseErr = false;
151
152 this.tableConfig = {
153 columns: [
154 ],
155 actions: [
156 {
157 label: 'delete',
158 icon: 'remove',
159 cb: (item) => {
160 this.Resource.delete({id: item.id}).$promise
161 .then(() => {
162 _.remove(this.data, (d) => d.id === item.id);
163 this.responseMsg = `${this.config.resource} with id ${item.id} successfully deleted`;
164 })
165 .catch(err => {
166 this.responseErr = err.data.detail || `Error while deleting ${this.config.resource} with id ${item.id}`;
167 });
168 },
169 color: 'red'
170 },
171 {
172 label: 'details',
173 icon: 'search',
174 cb: (item) => {
175 this.detailedItem = item;
176 }
177 }
178 ],
179 classes: 'table table-striped table-bordered table-responsive',
180 filter: 'field',
181 order: true,
182 pagination: {
183 pageSize: 10
184 }
185 };
186
187 this.formConfig = {
188 exclude: this.config.hiddenFields,
189 fields: {},
190 formName: `${this.config.resource}Form`,
191 actions: [
192 {
193 label: 'Save',
194 icon: 'ok',
195 cb: (item) => {
196 let p;
197 let isNew = true;
198
199 if(item.id){
200 p = item.$update();
201 isNew = false;
202 }
203 else {
204 p = item.$save();
205 }
206
207 p.then((res) => {
208 if(isNew){
209 this.data.push(angular.copy(res));
210 }
211 delete this.detailedItem;
212 this.responseMsg = `${this.config.resource} with id ${item.id} successfully saved`;
213 })
214 .catch((err) => {
215 this.responseErr = err.data.detail || `Error while saving ${this.config.resource} with id ${item.id}`;
216 })
217 },
218 class: 'success'
219 }
220 ]
221 };
222
223 this.cleanForm = () => {
224 delete this.detailedItem;
225 };
226
227 this.createItem = () => {
228 this.detailedItem = new this.Resource();
229 };
230
231 this.Resource = $injector.get(this.config.resource);
232
233 const getData = () => {
234 this.Resource.query().$promise
235 .then((res) => {
236
237 if(!res[0]){
238 this.data = res;
239 return;
240 }
241
242 let item = res[0];
243 let props = Object.keys(item);
244
245 _.remove(props, p => {
246 return p === 'id' || p === 'validators'
247 });
248
249 // TODO move out cb, non sense triggering a lot of times
250 if(angular.isArray(this.config.hiddenFields)){
251 props = _.difference(props, this.config.hiddenFields)
252 }
253
Matteo Scandoloe57712f2016-09-21 15:27:36 -0700254 props.forEach(p => {
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700255 let fieldConfig = {
Matteo Scandoloe57712f2016-09-21 15:27:36 -0700256 label: LabelFormatter.format(p),
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700257 prop: p
258 };
259
Matteo Scandoloe57712f2016-09-21 15:27:36 -0700260 fieldConfig.type = XosFormHelpers._getFieldFormat(item[p]);
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700261
262 this.tableConfig.columns.push(fieldConfig);
263 });
264
265 // build form structure
266 // TODO move in a pure function for testing purposes
Matteo Scandolo1d689852016-09-29 09:42:12 -0700267 props.forEach((p) => {
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700268 this.formConfig.fields[p] = {
Matteo Scandoloe57712f2016-09-21 15:27:36 -0700269 label: LabelFormatter.format(p).replace(':', ''),
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700270 type: XosFormHelpers._getFieldFormat(item[p])
271 };
272 });
Matteo Scandoloa5d03d52016-07-21 11:35:46 -0700273 this.data = res;
274 });
275 }
276
277 getData();
278 }
Matteo Scandolo1d689852016-09-29 09:42:12 -0700279 });
280})();