Matteo Scandolo | 4208f11 | 2016-08-10 17:02:02 -0700 | [diff] [blame^] | 1 | 'use strict'; |
| 2 | |
| 3 | angular.module('xos.UITutorial', [ |
| 4 | 'ngResource', |
| 5 | 'ngCookies', |
| 6 | 'ui.router', |
| 7 | 'xos.helpers' |
| 8 | ]) |
| 9 | .config(($stateProvider) => { |
| 10 | $stateProvider |
| 11 | .state('shell', { |
| 12 | url: '/', |
| 13 | template: '<js-shell></js-shell>' |
| 14 | }); |
| 15 | }) |
| 16 | .config(function($httpProvider){ |
| 17 | $httpProvider.interceptors.push('NoHyperlinks'); |
| 18 | }) |
| 19 | .directive('jsShell', function(){ |
| 20 | return { |
| 21 | restrict: 'E', |
| 22 | scope: {}, |
| 23 | bindToController: true, |
| 24 | controllerAs: 'vm', |
| 25 | templateUrl: 'templates/js-shell.tpl.html', |
| 26 | controller: function($injector){ |
| 27 | var history = new Josh.History({ key: 'helloworld.history'}); |
| 28 | var shell = Josh.Shell({history: history}); |
| 29 | |
| 30 | shell.onNewPrompt(function(callback) { |
| 31 | callback('[ngXosLib] $ '); |
| 32 | }); |
| 33 | |
| 34 | const errorHandler = (msg, done) => { |
| 35 | const errorTpl = _.template(`<span class="error">[ERROR] <%= msg %></span>`); |
| 36 | done(errorTpl({msg: msg})); |
| 37 | } |
| 38 | |
| 39 | const parseResponse = (res, done) => { |
| 40 | |
| 41 | // TODO @Arpit format res (it can be an array or an object), |
| 42 | // it is better if the output is a valid JSON (that we can copy and paste) |
| 43 | // TODO handle 204/No-Content response |
| 44 | if(angular.isArray(res)){ |
| 45 | res = res.map(i => { |
| 46 | return JSON.stringify(i, ['id', 'name', 'max_instances'], 2) + '<br/>'; |
| 47 | }); |
| 48 | } |
| 49 | else { |
| 50 | res = JSON.stringify(res, ['id', 'name', 'max_instances'], 2); |
| 51 | } |
| 52 | |
| 53 | done(res); |
| 54 | } |
| 55 | |
| 56 | const getAvailableResources = () => { |
| 57 | return angular.module('xos.helpers')._invokeQueue |
| 58 | .filter((d) => { |
| 59 | if(d[1] !== 'service'){ |
| 60 | return false; |
| 61 | } |
| 62 | const serviceDeps = d[2][1]; |
| 63 | return serviceDeps.indexOf('$resource') !== -1; |
| 64 | }) |
| 65 | .reduce((list, i) => list.concat([i[2][0]]), []); |
| 66 | } |
| 67 | |
| 68 | const listAvailableResources = (done) => { |
| 69 | const resources = getAvailableResources() |
| 70 | .reduce((html, i) => `${html}${i}<br/>`, ''); |
| 71 | done(resources); |
| 72 | } |
| 73 | |
| 74 | const consumeResource = (resourceName, method, args, done) => { |
| 75 | |
| 76 | if(getAvailableResources().indexOf(resourceName) === -1){ |
| 77 | return errorHandler(`Resource "${resourceName}" does not exists`, done); |
| 78 | } |
| 79 | |
| 80 | if(['query', 'get', 'save', '$save', 'delete'].indexOf(method) === -1){ |
| 81 | return errorHandler(`Method "${method}" not allowed`, done); |
| 82 | } |
| 83 | |
| 84 | let Resource; |
| 85 | try{ |
| 86 | Resource = $injector.get(resourceName); |
| 87 | |
| 88 | // TODO @Teo if get/delete check for arguments |
| 89 | let params = {}; |
| 90 | |
| 91 | // if the method require arguments checks for them |
| 92 | if(['get', '$save', 'delete'].indexOf(method) !== -1){ |
| 93 | if(args.length === 0){ |
| 94 | return errorHandler(`Method "${method}" require parameters`, done); |
| 95 | } |
| 96 | } |
| 97 | |
| 98 | // if there are arguments parse them |
| 99 | if(args.length > 0){ |
| 100 | params = eval(`(${args[0]})`); |
| 101 | } |
| 102 | |
| 103 | // if it is a query is not possible to use id as parameter |
| 104 | if(method === 'query' && angular.isDefined(params.id)){ |
| 105 | return errorHandler(`Is not possible to use "id" as filter in method "${method}", use "get" instead!`, done); |
| 106 | } |
| 107 | |
| 108 | Resource[method](params).$promise |
| 109 | .then(res => { |
| 110 | return parseResponse(res, done); |
| 111 | }); |
| 112 | } |
| 113 | catch(e){ |
| 114 | console.log(e); |
| 115 | return errorHandler(`Failed to inject resource "${resourceName}"`, done); |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | shell.setCommandHandler('resource', { |
| 120 | exec: (cmd, args, done) => { |
| 121 | switch(args[0]){ |
| 122 | case 'list': |
| 123 | return listAvailableResources(done); |
| 124 | break; |
| 125 | default: |
| 126 | // use the resource |
| 127 | const resourceName = args.shift(); |
| 128 | const method = args.shift(); |
| 129 | return consumeResource(resourceName, method, args, done); |
| 130 | } |
| 131 | }, |
| 132 | completion: function(cmd, arg, line, callback) { |
| 133 | const args = ['list'].concat(getAvailableResources()); |
| 134 | if(line.text.match(/resource\s[A-Z][a-z]+\s/)){ |
| 135 | // if arg is a resource, then return available methods |
| 136 | if(args.indexOf(arg) !== -1){ |
| 137 | arg = ''; |
| 138 | } |
| 139 | const methods = ['query', 'get', 'save', '$save', 'delete']; |
| 140 | return callback(shell.bestMatch(arg, methods)); |
| 141 | } |
| 142 | return callback(shell.bestMatch(arg, args)); |
| 143 | } |
| 144 | }) |
| 145 | |
| 146 | shell.setCommandHandler('slices', { |
| 147 | exec: (cmd, args, done) => { |
| 148 | Slices.query().$promise |
| 149 | .then(res => { |
| 150 | res = res.map(i => { |
| 151 | return JSON.stringify(i, ['id', 'name', 'max_instances'], 2); |
| 152 | }); |
| 153 | |
| 154 | res = res.reduce((response, item) => { |
| 155 | return `${response},<br>${item}`; |
| 156 | }); |
| 157 | |
| 158 | done(res); |
| 159 | }) |
| 160 | .catch(err => { |
| 161 | console.log(err); |
| 162 | done('An error occurred'); |
| 163 | }) |
| 164 | } |
| 165 | }); |
| 166 | |
| 167 | shell.activate(); |
| 168 | } |
| 169 | }; |
| 170 | }); |