Added instructions and tests
Change-Id: I18e491c4a0c188866dcad1f9db52c4f781054e62
diff --git a/views/ngXosViews/UITutorial/.eslintrc b/views/ngXosViews/UITutorial/.eslintrc
index c852748..a5bbd02 100644
--- a/views/ngXosViews/UITutorial/.eslintrc
+++ b/views/ngXosViews/UITutorial/.eslintrc
@@ -21,10 +21,10 @@
"eqeqeq": [2, "smart"],
"no-alert": 1,
"key-spacing": [1, { "beforeColon": false, "afterColon": true }],
- "indent": [2, 2],
+ "indent": [2, 2, { "SwitchCase": 1 }],
"no-irregular-whitespace": 1,
"eol-last": 0,
- "max-nested-callbacks": [2, 4],
+ "max-nested-callbacks": [1, 5],
"comma-spacing": [1, {"before": false, "after": true}],
"no-trailing-spaces": [1, { skipBlankLines: true }],
"no-unused-vars": [1, {"vars": "all", "args": "after-used"}],
diff --git a/views/ngXosViews/UITutorial/spec/errorHandler.test.js b/views/ngXosViews/UITutorial/spec/errorHandler.test.js
new file mode 100644
index 0000000..3f46330
--- /dev/null
+++ b/views/ngXosViews/UITutorial/spec/errorHandler.test.js
@@ -0,0 +1,22 @@
+'use strict';
+
+describe('The ErrorHandler service', () => {
+
+ var ErrorHandler, done;
+
+ beforeEach(module('xos.UITutorial'));
+ beforeEach(module('templates'));
+
+ beforeEach(inject(function (_ErrorHandler_) {
+ // The injector unwraps the underscores (_) from around the parameter names when matching
+ ErrorHandler = _ErrorHandler_;
+ done = jasmine.createSpy('done');
+ }));
+
+ describe('the print method', () => {
+ it('should return an html template', () => {
+ ErrorHandler.print('myError', done);
+ expect(done).toHaveBeenCalledWith(`<span class="error">[ERROR] myError</span>`)
+ });
+ });
+});
\ No newline at end of file
diff --git a/views/ngXosViews/UITutorial/spec/exploreCmd.test.js b/views/ngXosViews/UITutorial/spec/exploreCmd.test.js
new file mode 100644
index 0000000..a5d7cfe
--- /dev/null
+++ b/views/ngXosViews/UITutorial/spec/exploreCmd.test.js
@@ -0,0 +1,197 @@
+'use strict';
+
+describe('The ExploreCmd service', () => {
+
+ var ExploreCmd, ErrorHandler, ResponseHandler, done, shell, ResourceMock, rootScope;
+
+ beforeEach(module('xos.UITutorial'));
+ beforeEach(module('templates'));
+
+ beforeEach(() => {
+ module(function ($provide) {
+ $provide.value('Resource', ResourceMock);
+ })
+ });
+
+ beforeEach(inject(function (_ExploreCmd_, _ErrorHandler_, _ResponseHandler_, $rootScope) {
+ // The injector unwraps the underscores (_) from around the parameter names when matching
+ ExploreCmd = _ExploreCmd_;
+ ErrorHandler = _ErrorHandler_;
+ ResponseHandler = _ResponseHandler_;
+ rootScope = $rootScope;
+ done = jasmine.createSpy('done');
+ shell = {
+ setCommandHandler: jasmine.createSpy('setCommandHandler'),
+ bestMatch: jasmine.createSpy('bestMatch')
+ };
+ // binding the mock shell to the service (for easy testing)
+ ExploreCmd.shell = shell;
+ spyOn(console, 'error');
+
+ ResourceMock = {
+ query: jasmine.createSpy('query').and.callFake(() => {
+ var deferred = $q.defer();
+ deferred.resolve('Remote call result');
+ return {$promise: deferred.promise};
+ })
+ };
+ }));
+
+ it('should set the resouce command handler', () => {
+ ExploreCmd.setup(shell);
+ expect(shell.setCommandHandler).toHaveBeenCalledWith('resource', { exec: ExploreCmd.resourceExec, completion: ExploreCmd.resourceCompletion })
+ });
+
+ describe('the resourceCompletion function', () => {
+
+ beforeEach(() => {
+ spyOn(ExploreCmd, 'getAvailableResources').and.returnValue(['Sites', 'Slices']);
+ });
+
+ it('should suggest a resource list', () => {
+ ExploreCmd.resourceCompletion('resource', '', {text: 'resource'}, done)
+ expect(shell.bestMatch).toHaveBeenCalledWith('', [ 'list', 'Sites', 'Slices' ]);
+
+ ExploreCmd.resourceCompletion('resource', 'S', {text: 'resource S'}, done)
+ expect(shell.bestMatch).toHaveBeenCalledWith('S', [ 'list', 'Sites', 'Slices' ]);
+ });
+
+ it('should suggest a method list', () => {
+ ExploreCmd.resourceCompletion('resource', '', {text: 'resource Sites '}, done)
+ expect(shell.bestMatch).toHaveBeenCalledWith('', [ 'query', 'get', 'save', '$save', 'delete' ]);
+
+ ExploreCmd.resourceCompletion('resource', 'q', {text: 'resource Sites q'}, done)
+ expect(shell.bestMatch).toHaveBeenCalledWith('q', [ 'query', 'get', 'save', '$save', 'delete' ]);
+ });
+ });
+
+ describe('the resourceExec function', () => {
+
+ beforeEach(() => {
+ spyOn(ExploreCmd, 'listAvailableResources');
+ spyOn(ExploreCmd, 'consumeResource');
+ });
+
+ it('should list available resources', () => {
+ ExploreCmd.resourceExec('explore', ['list'], done);
+ expect(ExploreCmd.listAvailableResources).toHaveBeenCalledWith(done);
+ });
+
+ it('should use a resource', () => {
+ ExploreCmd.resourceExec('explore', ['Resource', 'query'], done);
+ expect(ExploreCmd.consumeResource).toHaveBeenCalledWith('Resource', 'query', [], done);
+ });
+ });
+
+ describe('the getAvailableResources function', () => {
+
+ beforeEach(() => {
+ spyOn(angular, 'module').and.returnValue({
+ _invokeQueue: [
+ ['$provide', 'service', ['Sites', ['$resource']]],
+ ['$provide', 'service', ['Slices', ['$q', '$resource']]],
+ ['$provide', 'factory', ['_', []]],
+ ['$provide', 'service', ['helper', ['Slices']]]
+ ]
+ });
+ });
+
+ it('should return a list of resources in the angular app', () => {
+ const resources = ExploreCmd.getAvailableResources();
+ expect(resources).toEqual(['Sites', 'Slices']);
+ });
+ });
+
+ describe('the listAvailableResources function', () => {
+ beforeEach(() => {
+ spyOn(ExploreCmd, 'getAvailableResources').and.returnValue(['Sites', 'Slices']);
+ });
+
+ it('should format resource in an html template', () => {
+ ExploreCmd.listAvailableResources(done);
+ expect(ExploreCmd.getAvailableResources).toHaveBeenCalled();
+ expect(done).toHaveBeenCalledWith(`Sites<br/>Slices<br/>`);
+ });
+ });
+
+ describe('the consumeResource function', () => {
+ beforeEach(() => {
+ spyOn(ExploreCmd, 'getAvailableResources').and.returnValue(['Resource', 'Fake']);
+ spyOn(ErrorHandler, 'print');
+ });
+
+ it('should notify that a resource does not exists', () => {
+ ExploreCmd.consumeResource('Test', null, null, done);
+ expect(ErrorHandler.print).toHaveBeenCalledWith(`Resource "Test" does not exists`, done)
+ });
+
+ it('should notify that a method does not exists', () => {
+ ExploreCmd.consumeResource('Resource', 'test', null, done);
+ expect(ErrorHandler.print).toHaveBeenCalledWith(`Method "test" not allowed`, done)
+ });
+
+ const methodsWithParams = ['get', '$save', 'delete'];
+ methodsWithParams.forEach(method => {
+ it(`should notify that the ${method} method require parameters`, () => {
+ ExploreCmd.consumeResource('Resource', method, [], done);
+ expect(ErrorHandler.print).toHaveBeenCalledWith(`Method "${method}" require parameters`, done)
+ });
+ });
+
+ it('should not accept id as parameter for the query method', () => {
+ ExploreCmd.consumeResource('Resource', 'query', ['{id:1}'], done);
+ expect(ErrorHandler.print).toHaveBeenCalledWith(`Is not possible to use "id" as filter in method "query", use "get" instead!`, done)
+ });
+
+ it('should notify the user in case of malformed parameters', () => {
+ ExploreCmd.consumeResource('Resource', 'query', ['{child: 3}'], done);
+ expect(ErrorHandler.print).toHaveBeenCalledWith(`Parameter is not valid, it shoudl be in the form of: <code>{id:1}</code>, with no spaces`, done)
+ pending();
+ });
+
+ describe('when called with the correct parameters', () => {
+
+ let deferred;
+ beforeEach(inject(($q) => {
+ spyOn(ResponseHandler, 'parse');
+
+ deferred = $q.defer();
+ ResourceMock = {
+ query: jasmine.createSpy('query').and.callFake(function(){
+ return {$promise: deferred.promise};
+ })
+ };
+ }));
+
+ it('should notify the user if an error occurred while loading the resource', () => {
+ ExploreCmd.consumeResource('Fake', 'query', [], done);
+ expect(console.error).toHaveBeenCalled();
+ expect(ErrorHandler.print).toHaveBeenCalledWith('Failed to inject resource "Fake"', done);
+ });
+
+ it('should call a resource and return the results', () => {
+ ExploreCmd.consumeResource('Resource', 'query', [], done);
+ deferred.resolve([]);
+ rootScope.$apply();
+ expect(ErrorHandler.print).not.toHaveBeenCalled()
+ expect(ResponseHandler.parse).toHaveBeenCalledWith([], 'Resource.query()', done);
+ });
+
+ it('should call a resource with parameters and return the results', () => {
+ ExploreCmd.consumeResource('Resource', 'query', ['{child:3}'], done);
+ deferred.resolve([]);
+ rootScope.$apply();
+ expect(ErrorHandler.print).not.toHaveBeenCalled()
+ expect(ResponseHandler.parse).toHaveBeenCalledWith([], 'Resource.query({"child":3})', done);
+ });
+
+ it('should call a resource and display a not found message', () => {
+ ExploreCmd.consumeResource('Resource', 'query', [], done);
+ deferred.reject({status: 404, data: {detail: 'Not Found.'}});
+ rootScope.$apply();
+ expect(ErrorHandler.print).toHaveBeenCalledWith('Resource with method "query" and parameters {} Not Found.', done)
+ expect(ResponseHandler.parse).not.toHaveBeenCalled();
+ });
+ });
+ });
+});
\ No newline at end of file
diff --git a/views/ngXosViews/UITutorial/spec/responseHandler.test.js b/views/ngXosViews/UITutorial/spec/responseHandler.test.js
new file mode 100644
index 0000000..4ce26be
--- /dev/null
+++ b/views/ngXosViews/UITutorial/spec/responseHandler.test.js
@@ -0,0 +1,46 @@
+'use strict';
+
+describe('The ResponseHandler service', () => {
+
+ var ResponseHandler, done;
+
+ beforeEach(module('xos.UITutorial'));
+ beforeEach(module('templates'));
+
+ beforeEach(inject(function (_ResponseHandler_) {
+ // The injector unwraps the underscores (_) from around the parameter names when matching
+ ResponseHandler = _ResponseHandler_;
+ done = jasmine.createSpy('done');
+ }));
+
+ describe('the parse method', () => {
+ it('should return an html template for a collection', () => {
+ const collection = [
+ {id: 1, deleted: true, name: 'one'},
+ {id: 2, deleted: true, name: 'two'}
+ ];
+
+ const collectionHtml = `
+ <div>
+ <p>Corresponding js code: <code>jsCode</code></p>
+ <div class="json"><div class="jsonCollection">[<div class="jsonObject">{"id":1,"name":"one"},</code></div><div class="jsonObject">{"id":2,"name":"two"}</code></div>]</div></div>
+ </div>
+ `;
+ ResponseHandler.parse(collection, 'jsCode', done);
+ expect(done).toHaveBeenCalledWith(collectionHtml)
+ });
+
+ it('should return an html template for an object', () => {
+ const object = {id: 1, deleted: true, name: 'one'};
+
+ const objectHtml = `
+ <div>
+ <p>Corresponding js code: <code></code></p>
+ <div class="json"><div class="jsonObject">{"id":1,"name":"one"}</code></div></div>
+ </div>
+ `;
+ ResponseHandler.parse(object, '', done);
+ expect(done).toHaveBeenCalledWith(objectHtml)
+ });
+ });
+});
\ No newline at end of file
diff --git a/views/ngXosViews/UITutorial/spec/sample.test.js b/views/ngXosViews/UITutorial/spec/sample.test.js
deleted file mode 100644
index 9e16127..0000000
--- a/views/ngXosViews/UITutorial/spec/sample.test.js
+++ /dev/null
@@ -1,37 +0,0 @@
-'use strict';
-
-describe('The User List', () => {
-
- var scope, element, isolatedScope, httpBackend;
-
- beforeEach(module('xos.UITutorial'));
- beforeEach(module('templates'));
-
- beforeEach(inject(function($httpBackend, $compile, $rootScope){
-
- httpBackend = $httpBackend;
- // Setting up mock request
- $httpBackend.expectGET('/api/core/users/?no_hyperlinks=1').respond([
- {
- email: 'matteo.scandolo@gmail.com',
- firstname: 'Matteo',
- lastname: 'Scandolo'
- }
- ]);
-
- scope = $rootScope.$new();
- element = angular.element('<users-list></users-list>');
- $compile(element)(scope);
- scope.$digest();
- isolatedScope = element.isolateScope().vm;
- }));
-
- xit('should load 1 users', () => {
- httpBackend.flush();
- expect(isolatedScope.users.length).toBe(1);
- expect(isolatedScope.users[0].email).toEqual('matteo.scandolo@gmail.com');
- expect(isolatedScope.users[0].firstname).toEqual('Matteo');
- expect(isolatedScope.users[0].lastname).toEqual('Scandolo');
- });
-
-});
\ No newline at end of file
diff --git a/views/ngXosViews/UITutorial/spec/shell.test.js b/views/ngXosViews/UITutorial/spec/shell.test.js
new file mode 100644
index 0000000..19ea63e
--- /dev/null
+++ b/views/ngXosViews/UITutorial/spec/shell.test.js
@@ -0,0 +1,29 @@
+'use strict';
+
+describe('The Js Shell directive', () => {
+
+ var scope, element, isolatedScope, shellSpy;
+
+ beforeEach(module('xos.UITutorial'));
+ beforeEach(module('templates'));
+
+ beforeEach(inject(function($compile, $rootScope){
+ scope = $rootScope.$new();
+ element = angular.element('<js-shell></js-shell>');
+ $compile(element)(scope);
+ scope.$digest();
+ isolatedScope = element.isolateScope().vm;
+ spyOn(isolatedScope.shell, 'setCommandHandler');
+ spyOn(isolatedScope.shell, 'activate');
+ }));
+
+ // NOTE see http://stackoverflow.com/questions/38906605/angular-jasmine-testing-immediatly-invoked-functions-inside-a-directive-contr
+
+ xit('should register the explore command', () => {
+ expect(isolatedScope.shell.setCommandHandler).toHaveBeenCalled();
+ });
+
+ xit('should activate the shell', () => {
+ expect(isolatedScope.shell.activate).toHaveBeenCalled();
+ });
+});
\ No newline at end of file
diff --git a/views/ngXosViews/UITutorial/spec/templateHandler.test.js b/views/ngXosViews/UITutorial/spec/templateHandler.test.js
new file mode 100644
index 0000000..0af68b9
--- /dev/null
+++ b/views/ngXosViews/UITutorial/spec/templateHandler.test.js
@@ -0,0 +1,22 @@
+'use strict';
+
+describe('The TemplateHandler service', () => {
+
+ var TemplateHandler;
+
+ beforeEach(module('xos.UITutorial'));
+ beforeEach(module('templates'));
+
+ beforeEach(inject(function (_TemplateHandler_) {
+ TemplateHandler = _TemplateHandler_;
+ }));
+
+ const templates = ['error', 'instructions', 'resourcesResponse'];
+
+ templates.forEach(t => {
+ it(`should have a ${t} template`, () => {
+ expect(TemplateHandler[t]).toBeDefined();
+ expect(angular.isFunction(TemplateHandler[t])).toBeTruthy();
+ });
+ });
+});
\ No newline at end of file
diff --git a/views/ngXosViews/UITutorial/src/css/main.css b/views/ngXosViews/UITutorial/src/css/main.css
index 3684934..d008cb5 100644
--- a/views/ngXosViews/UITutorial/src/css/main.css
+++ b/views/ngXosViews/UITutorial/src/css/main.css
@@ -7,14 +7,19 @@
height: 400px;
background: #002b36;
padding: 10px;
- overflow: scroll; }
+ overflow: scroll;
+ color: #93a1a1; }
#xosUITutorial js-shell #shell-panel .prompt {
color: #d33682; }
+ #xosUITutorial js-shell #shell-panel .input {
+ color: #268bd2; }
#xosUITutorial js-shell #shell-panel .cursor {
color: #2aa198; }
#xosUITutorial js-shell #shell-panel .error {
color: #dc322f; }
- #xosUITutorial js-shell #shell-panel #shell-view {
- color: #93a1a1; }
- #xosUITutorial js-shell #shell-panel #shell-view > div > div {
- color: #268bd2; }
+ #xosUITutorial js-shell #shell-panel #shell-view > div > div {
+ color: #268bd2; }
+ #xosUITutorial js-shell #shell-panel #shell-view .jsonObject {
+ white-space: nowrap; }
+ #xosUITutorial js-shell #shell-panel #shell-view .jsonCollection > .jsonObject {
+ margin-left: 10px; }
diff --git a/views/ngXosViews/UITutorial/src/index.html b/views/ngXosViews/UITutorial/src/index.html
index 6819b46..d325f9c 100644
--- a/views/ngXosViews/UITutorial/src/index.html
+++ b/views/ngXosViews/UITutorial/src/index.html
@@ -39,6 +39,7 @@
<!-- inject:js -->
<script src="/vendor/ng-xos-lib/dist/ngXosHelpers.min.js"></script>
<script src="/.tmp/main.js"></script>
+<script src="/.tmp/templateHandler.js"></script>
<script src="/.tmp/responseHandler.js"></script>
<script src="/.tmp/exploreCmd.js"></script>
<script src="/.tmp/errorHandler.js"></script>
diff --git a/views/ngXosViews/UITutorial/src/js/errorHandler.js b/views/ngXosViews/UITutorial/src/js/errorHandler.js
index dbe41f4..aa75d38 100644
--- a/views/ngXosViews/UITutorial/src/js/errorHandler.js
+++ b/views/ngXosViews/UITutorial/src/js/errorHandler.js
@@ -1,10 +1,9 @@
(function () {
'use strict';
angular.module('xos.UITutorial')
- .service('ErrorHandler', function(){
+ .service('ErrorHandler', function(TemplateHandler){
this.print = (msg, done) => {
- const errorTpl = _.template(`<span class="error">[ERROR] <%= msg %></span>`);
- done(errorTpl({msg: msg}));
+ done(TemplateHandler.error({msg: msg}));
};
});
})();
\ No newline at end of file
diff --git a/views/ngXosViews/UITutorial/src/js/exploreCmd.js b/views/ngXosViews/UITutorial/src/js/exploreCmd.js
index d4bba90..0aba8fa 100644
--- a/views/ngXosViews/UITutorial/src/js/exploreCmd.js
+++ b/views/ngXosViews/UITutorial/src/js/exploreCmd.js
@@ -3,36 +3,41 @@
angular.module('xos.UITutorial')
.service('ExploreCmd', function($injector, ResponseHandler, ErrorHandler){
- this.setup = (shell) => {
- shell.setCommandHandler('resource', {
- exec: (cmd, args, done) => {
- switch(args[0]){
- case 'list':
- return listAvailableResources(done);
- break;
- default:
- // use the resource
- const resourceName = args.shift();
- const method = args.shift();
- return consumeResource(resourceName, method, args, done);
- }
- },
- completion: function(cmd, arg, line, callback) {
- const args = ['list'].concat(getAvailableResources());
- if(line.text.match(/resource\s[A-Z][a-z]+\s/)){
- // if arg is a resource, then return available methods
- if(args.indexOf(arg) !== -1){
- arg = '';
- }
- const methods = ['query', 'get', 'save', '$save', 'delete'];
- return callback(shell.bestMatch(arg, methods));
- }
- return callback(shell.bestMatch(arg, args));
+ this.resourceExec = (cmd, args, done) => {
+ switch(args[0]){
+ case 'list':
+ return this.listAvailableResources(done);
+ break;
+ default:
+ // use the resource
+ const resourceName = args.shift();
+ const method = args.shift();
+ return this.consumeResource(resourceName, method, args, done);
+ }
+ };
+
+ this.resourceCompletion = (cmd, arg, line, done) => {
+ const args = ['list'].concat(this.getAvailableResources());
+ if(line.text.match(/resource\s[A-Z][a-z]+\s/)){
+ // if arg is a resource, then return available methods
+ if(args.indexOf(arg) !== -1){
+ arg = '';
}
+ const methods = ['query', 'get', 'save', '$save', 'delete'];
+ return done(this.shell.bestMatch(arg, methods));
+ }
+ return done(this.shell.bestMatch(arg, args));
+ };
+
+ this.setup = (shell) => {
+ this.shell = shell;
+ shell.setCommandHandler('resource', {
+ exec: this.resourceExec,
+ completion: this.resourceCompletion
});
};
- const getAvailableResources = () => {
+ this.getAvailableResources = () => {
return angular.module('xos.helpers')._invokeQueue
.filter((d) => {
if(d[1] !== 'service'){
@@ -44,17 +49,18 @@
.reduce((list, i) => list.concat([i[2][0]]), []);
}
- const listAvailableResources = (done) => {
- const resources = getAvailableResources()
+ this.listAvailableResources = (done) => {
+ // TODO use a template
+ const resources = this.getAvailableResources()
.reduce((html, i) => `${html}${i}<br/>`, '');
done(resources);
}
- const consumeResource = (resourceName, method, args, done) => {
+ this.consumeResource = (resourceName, method, args, done) => {
// TODO if not resourceName/method print cmd instructions
- if(getAvailableResources().indexOf(resourceName) === -1){
+ if(this.getAvailableResources().indexOf(resourceName) === -1){
return ErrorHandler.print(`Resource "${resourceName}" does not exists`, done);
}
@@ -62,36 +68,43 @@
return ErrorHandler.print(`Method "${method}" not allowed`, done);
}
+ // TODO @Teo if get/delete check for arguments
+ let params = {};
+
+ // if the method require arguments checks for them
+ if(['get', '$save', 'delete'].indexOf(method) !== -1){
+ if(args.length === 0){
+ return ErrorHandler.print(`Method "${method}" require parameters`, done);
+ }
+ }
+
+ // if there are arguments parse them
+ // TODO wrap in a try catch, we have no guarantee that a user insert the correct params
+ if(args.length > 0){
+ params = eval(`(${args[0]})`);
+ }
+
+ // if it is a query is not possible to use id as parameter
+ if(method === 'query' && angular.isDefined(params.id)){
+ return ErrorHandler.print(`Is not possible to use "id" as filter in method "${method}", use "get" instead!`, done);
+ }
+
let Resource;
try{
Resource = $injector.get(resourceName);
-
- // TODO @Teo if get/delete check for arguments
- let params = {};
-
- // if the method require arguments checks for them
- if(['get', '$save', 'delete'].indexOf(method) !== -1){
- if(args.length === 0){
- return ErrorHandler.print(`Method "${method}" require parameters`, done);
- }
- }
-
- // if there are arguments parse them
- if(args.length > 0){
- params = eval(`(${args[0]})`);
- }
-
- // if it is a query is not possible to use id as parameter
- if(method === 'query' && angular.isDefined(params.id)){
- return ErrorHandler.print(`Is not possible to use "id" as filter in method "${method}", use "get" instead!`, done);
- }
-
Resource[method](params).$promise
.then(res => {
- return ResponseHandler.parse(res, done);
+ const jsCode = `${resourceName}.${method}(${Object.keys(params).length > 0 ? JSON.stringify(params): ''})`;
+ return ResponseHandler.parse(res, jsCode, done);
+ })
+ .catch(e => {
+ if(e.status === 404){
+ return ErrorHandler.print(`${resourceName} with method "${method}" and parameters ${JSON.stringify(params)} ${e.data.detail}`, done);
+ }
});
}
catch(e){
+ console.error(e);
return ErrorHandler.print(`Failed to inject resource "${resourceName}"`, done);
}
};
diff --git a/views/ngXosViews/UITutorial/src/js/main.js b/views/ngXosViews/UITutorial/src/js/main.js
index bc5c27e..c89f1da 100644
--- a/views/ngXosViews/UITutorial/src/js/main.js
+++ b/views/ngXosViews/UITutorial/src/js/main.js
@@ -16,7 +16,7 @@
.config(function($httpProvider){
$httpProvider.interceptors.push('NoHyperlinks');
})
-.directive('jsShell', function(){
+.directive('jsShell', function(TemplateHandler){
return {
restrict: 'E',
scope: {},
@@ -24,23 +24,28 @@
controllerAs: 'vm',
templateUrl: 'templates/js-shell.tpl.html',
controller: function(ExploreCmd){
- var history = new Josh.History({ key: 'helloworld.history'});
- var shell = Josh.Shell({history: history});
+ var history = new Josh.History({ key: 'jsshell.history'});
+ this.shell = Josh.Shell({history: history});
- shell.onNewPrompt(function(done) {
+ this.shell.onNewPrompt(done => {
done('[ngXosLib] $ ');
});
- shell.setCommandHandler('explore', {
+ this.shell.setCommandHandler('explore', {
exec: (cmd, args, done) => {
- ExploreCmd.setup(shell);
- done();
+ ExploreCmd.setup(this.shell);
+ done(TemplateHandler.instructions({
+ title: `You can now explore the API use angular $resouces!`,
+ messages: [
+ `Use <code>resource list</code> to list all the available resources and <code>resource {resoureName} {method} {?paramters}</code> to call the API.`,
+ `An example command is <code>resource Slices query</code>`,
+ `You can also provide paramters with <code>resource Slices query {max_instances: 10}</code>`
+ ]
+ }));
}
});
-
-
- shell.activate();
+ this.shell.activate();
}
};
});
\ No newline at end of file
diff --git a/views/ngXosViews/UITutorial/src/js/responseHandler.js b/views/ngXosViews/UITutorial/src/js/responseHandler.js
index 801129e..e343dda 100644
--- a/views/ngXosViews/UITutorial/src/js/responseHandler.js
+++ b/views/ngXosViews/UITutorial/src/js/responseHandler.js
@@ -1,27 +1,47 @@
(function () {
'use strict';
angular.module('xos.UITutorial')
- .service('ResponseHandler', function(){
- this.parse = (res, done) => {
- var compiled = _.template('<div><pre><%- JSON.stringify(val,null,1) %></div></pre>');
- var compiledArray = _.template('<% _.forEach(valueArr, function(item) { %><div><pre><%- JSON.stringify(item) %></pre></div><%}); %>');
- var resFunc = function (res) {
- let retVar;
- let exclude = ['deleted','enabled','enacted','exposed_ports','lazy_blocked','created','validators','controllers','backend_status','backend_register','policed','no_policy','write_protect','no_sync','updated'];
- if(_.isArray(res)) {
- retVar = [];
- retVar = _.map(res, (o)=> {
- return _.omit(o, exclude);
- });
- retVar = compiledArray({'valueArr':retVar});
- }
- else{
- retVar = _.omit(res,exclude);
- retVar = compiled({'val':retVar} );
- }
- return retVar;
+ .service('ResponseHandler', function(TemplateHandler){
+
+ const exclude = [
+ 'deleted',
+ 'enabled',
+ 'enacted',
+ 'exposed_ports',
+ 'lazy_blocked',
+ 'created',
+ 'validators',
+ 'controllers',
+ 'backend_status',
+ 'backend_register',
+ 'policed',
+ 'no_policy',
+ 'write_protect',
+ 'no_sync',
+ 'updated'
+ ];
+
+ this.parseObject = (obj, comma = '') => {
+ obj = _.omit(obj, exclude);
+ return TemplateHandler.jsonObject({'obj': obj, comma: comma});
+ };
+
+ this.parseCollection = (array) => {
+ array = array.map((o, i) => `${this.parseObject(o, i === (array.length - 1) ? '':',')}`);
+ return TemplateHandler.jsonCollection({'collection': array});
+ };
+
+ this.parse = (res, jsCode, done) => {
+ if(_.isArray(res)) {
+ res = this.parseCollection(res);
}
- done( resFunc(res));
+ else{
+ res = this.parseObject(res);
+ }
+ done(TemplateHandler.resourcesResponse({
+ jsCode: jsCode,
+ res: res
+ }));
};
});
})();
\ No newline at end of file
diff --git a/views/ngXosViews/UITutorial/src/js/templateHandler.js b/views/ngXosViews/UITutorial/src/js/templateHandler.js
new file mode 100644
index 0000000..752b214
--- /dev/null
+++ b/views/ngXosViews/UITutorial/src/js/templateHandler.js
@@ -0,0 +1,26 @@
+(function () {
+ 'use strict';
+ angular.module('xos.UITutorial')
+ .service('TemplateHandler', function(_){
+
+ this.error = _.template(`<span class="error">[ERROR] <%= msg %></span>`);
+
+ this.instructions = _.template(`
+ <div>
+ <strong><%= title %></strong>
+ <% _.forEach(messages, function(m) { %><p><%= m %></p><% }); %>
+ </div>
+ `);
+
+ this.resourcesResponse = _.template(`
+ <div>
+ <p>Corresponding js code: <code><%= jsCode %></code></p>
+ <div class="json"><%= res %></div>
+ </div>
+ `);
+
+ this.jsonObject = _.template(`<div class="jsonObject"><%= JSON.stringify(obj) %><%=comma%></code></div>`);
+
+ this.jsonCollection = _.template(`<div class="jsonCollection">[<% _.forEach(collection, function(item) { %><%= item %><%}); %>]</div>`);
+ });
+})();
\ No newline at end of file
diff --git a/views/ngXosViews/UITutorial/src/sass/main.scss b/views/ngXosViews/UITutorial/src/sass/main.scss
index 83ea377..f3b0496 100644
--- a/views/ngXosViews/UITutorial/src/sass/main.scss
+++ b/views/ngXosViews/UITutorial/src/sass/main.scss
@@ -28,11 +28,16 @@
background: $background;
padding: 10px;
overflow: scroll;
+ color: $emph;
.prompt {
color: $magenta;
}
+ .input {
+ color: $blue;
+ }
+
.cursor {
color: $cyan;
}
@@ -42,11 +47,20 @@
}
#shell-view {
- color: $emph;
>div>div{
color: $blue;
}
+
+ .jsonObject {
+ white-space: nowrap;
+ }
+
+ .jsonCollection {
+ >.jsonObject{
+ margin-left: 10px;
+ }
+ }
}
}
}
diff --git a/views/ngXosViews/UITutorial/src/templates/js-shell.tpl.html b/views/ngXosViews/UITutorial/src/templates/js-shell.tpl.html
index 543006d..8799fd4 100644
--- a/views/ngXosViews/UITutorial/src/templates/js-shell.tpl.html
+++ b/views/ngXosViews/UITutorial/src/templates/js-shell.tpl.html
@@ -1,3 +1,6 @@
<div id="shell-panel">
+ <div>
+ Type <code>help</code> or hit <code>TAB</code> for a list of commands.
+ </div>
<div id="shell-view"></div>
</div>
\ No newline at end of file