diff --git a/Gruntfile.js b/Gruntfile.js deleted file mode 100644 index 898e323..0000000 --- a/Gruntfile.js +++ /dev/null @@ -1,39 +0,0 @@ -module.exports = function (grunt) { - 'use strict'; - - var DEFAULT_HOST = 'developer.cumulocity.com', - DEFAULT_PROTOCOL = 'https', - host = DEFAULT_HOST, - protocol = DEFAULT_PROTOCOL; - - if (grunt.option('host')) { - host = grunt.option('host'); - } - - if (grunt.option('protocol')) { - protocol = grunt.option('protocol'); - } - - grunt.config('cumulocity.host', host); - grunt.config('cumulocity.protocol', protocol); - - grunt.config('paths.root', './'); - grunt.config('paths.temp', '.tmp'); - grunt.config('paths.build', 'build'); - grunt.config('paths.plugins', 'plugins'); - grunt.config('paths.bower', 'bower_components'); - - //Load cumulocity grunt tasks - grunt.loadNpmTasks('grunt-cumulocity-ui-tasks'); - - grunt.registerTask('server', [ - 'pluginPreAll', - 'connect', - 'watch' - ]); - - grunt.registerTask('build', [ - 'pluginBuildAll' - ]); - -}; \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..69a8782 --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2015 Cumulocity GmbH + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 72e1e89..3deb803 100644 --- a/README.md +++ b/README.md @@ -6,35 +6,29 @@ Repository contains an application with sample plugins described in [Plugin Deve Plugins ------- -* myplugin - +* **myplugin** Simple hello world plugin. -* branding - -Sample branding plugin which changes the icon displayed in Application Switcher menu. It can be developed further by adding more CSS/LESS rules to alter the whole appearance of the application. Base layout and styling is provided by standard Cumulocity branding plugin (`core/c8yBranding`). - -* deviceContact +* **myBranding** +Sample branding base on the base (`core/c8yBranding`). You can inspect the less files to inspect the many less variables available for configuration. -Application embedded plugin that adds a new tab to device details view named *Contact* which displays a simple form for providing contact details. Contact details are stored in Managed Object’s data. - - -* deviceEventsRealTime +* **deviceContact** +Application embedded plugin that adds a new tab to device details view named *Contact* which displays a simple form for providing contact details. Contact details are stored in Managed Object’s data. +* **deviceEventsRealTime** Application embedded plugin that adds a new tab to device details view and displays the list of incoming device events in real-time. How to run the examples ----------------------- - -* clone [`cumulocity-ui-plugin-examples`](https://bitbucket.org/m2m/cumulocity-ui-plugin-examples) repository, -* run `npm install`, -* adjust application manifest file `cumulocity.json`: +* Make sure you have node.js >6.7 installed +* Install the Cumulocity CLI globally: ```npm i cumulocity-tools -g``` +* Clone or download [`cumulocity-ui-plugin-examples`](https://bitbucket.org/m2m/cumulocity-ui-plugin-examples) repository, +* Run `c8y install latest`, +* Adjust application manifest file `cumulocity.json`: * change `contextPath` to something unique for your tenant, * change `key` to something unique for platform, (?) * change `name` to something unique for platform, (?) -* run `grunt appRegister:noImports` to register the application without plugins, -* run `grunt pluginRegisterAll` to register plugins for application, -* run `grunt appRegister` again to register the application with plugins, -* run `grunt server` to start local server, -* visit *http://localhost:8000/apps/* to see the application working. +* Create the application on your tenant: ```c8y deploy:app ``` +* Run local development server: *c8y server* +* Open in browser: *http://localhost:9000/apps/* diff --git a/plugins/deviceContact/cumulocity.json b/plugins/deviceContact/cumulocity.json index 1caf82b..9695ff4 100644 --- a/plugins/deviceContact/cumulocity.json +++ b/plugins/deviceContact/cumulocity.json @@ -2,13 +2,11 @@ "name": "Device Details - Contact", "description": "Plugin adds a Contact tab to Device Details view", "category": "Examples", - "icon": "bell", - "color": "#F2DF0F", "ngModules": [ "myapp.deviceContact" ], "js": [ "index.js", - "controllers/deviceContact.js" + "deviceContact.controller.js" ] } diff --git a/plugins/deviceContact/controllers/deviceContact.js b/plugins/deviceContact/deviceContact.controller.js similarity index 64% rename from plugins/deviceContact/controllers/deviceContact.js rename to plugins/deviceContact/deviceContact.controller.js index b8d07e3..5becb90 100644 --- a/plugins/deviceContact/controllers/deviceContact.js +++ b/plugins/deviceContact/deviceContact.controller.js @@ -1,8 +1,11 @@ -angular.module('myapp.deviceContact') -.controller('deviceContactCtrl', ['$scope', '$routeParams', 'c8yDevices', 'c8yAlert', - function ($scope, $routeParams, c8yDevices, c8yAlert) { - 'use strict'; - +(function() { + 'use strict'; + + angular.module('myapp.deviceContact') + .controller('deviceContactCtrl', DeviceContactController); + + function DeviceContactController($scope, $routeParams, c8yDevices, c8yAlert) { + function load() { c8yDevices.detail($routeParams.deviceId).then(function (res) { var device = res.data; @@ -10,7 +13,7 @@ angular.module('myapp.deviceContact') $scope.device.c8y_Contact = device.c8y_Contact; }); } - + function save(device) { c8yDevices.save(device).then(onSave); } @@ -24,4 +27,5 @@ angular.module('myapp.deviceContact') load(); } -]); + +}()); diff --git a/plugins/deviceContact/views/deviceContact.html b/plugins/deviceContact/deviceContact.html similarity index 100% rename from plugins/deviceContact/views/deviceContact.html rename to plugins/deviceContact/deviceContact.html diff --git a/plugins/deviceContact/index.js b/plugins/deviceContact/index.js index 71f239b..b551348 100644 --- a/plugins/deviceContact/index.js +++ b/plugins/deviceContact/index.js @@ -1,10 +1,17 @@ -angular.module('myapp.deviceContact', []) - .config(['c8yViewsProvider', function (c8yViewsProvider) { +(function() { + 'use strict'; + + angular.module('myapp.deviceContact', []) + .config(config); + + function config(c8yViewsProvider) { c8yViewsProvider.when('/device/:deviceId', { name: 'Contact', icon: 'envelope-o', priority: 1000, - templateUrl: ':::PLUGIN_PATH:::/views/deviceContact.html', + templateUrl: ':::PLUGIN_PATH:::/deviceContact.html', controller: 'deviceContactCtrl' }); - }]); \ No newline at end of file + } + +}()); diff --git a/plugins/deviceEventsRealTime/controllers/deviceEventsRealTimeCtrl.js b/plugins/deviceEventsRealTime/controllers/deviceEventsRealTimeCtrl.js deleted file mode 100644 index 6c275cd..0000000 --- a/plugins/deviceEventsRealTime/controllers/deviceEventsRealTimeCtrl.js +++ /dev/null @@ -1,50 +0,0 @@ -angular.module('myapp.deviceEventsRealTime') -.controller('deviceEventsRealTimeCtrl', ['$scope', '$routeParams', 'c8yNotifications', 'c8yAlert', 'c8yCepModule', -function ($scope, $routeParams, c8yNotifications, c8yAlert, c8yCepModule) { - var deviceId = $routeParams.deviceId, - eventsChannel = '/events/' + deviceId, - cepModule = { - name: 'c8yui_realtime_device_events', - body: 'insert into\n' + - ' SendNotification\n' + - 'select\n' + - ' e.event as payload,\n' + - ' "events/" || e.event.source.value as channelName\n' + - 'from\n' + - ' EventCreated e;', - status: 'DEPLOYED' - }, - subscription; - - function subscribe() { - if (!subscription) { - c8yCepModule.createOrDeploy(cepModule) - .then(c8yNotifications.configure) - .then(angular.bind({}, c8yNotifications.subscribe, eventsChannel)) - .then(function (_subscription) { - c8yAlert.success('Connected! Waiting for incoming events...'); - subscription = _subscription; - subscription.$on('message', onMessage); - }); - } - } - - function onMessage(evt, event) { - $scope.events.push(event); - - while ($scope.events.length > 100) { - $scope.events.shift(); - } - } - - function onDestroy() { - if (subscription && subscription.unsubscribe) { - subscription.unsubscribe(); - } - } - - $scope.events = []; - $scope.$on('$destroy', onDestroy); - - subscribe(); -}]); \ No newline at end of file diff --git a/plugins/deviceEventsRealTime/cumulocity.json b/plugins/deviceEventsRealTime/cumulocity.json index d837900..4933328 100644 --- a/plugins/deviceEventsRealTime/cumulocity.json +++ b/plugins/deviceEventsRealTime/cumulocity.json @@ -2,13 +2,11 @@ "name": "Device Events in Real-Time", "description": "Plugin adds a tab to Device Details with events displayed in real-time", "category": "Examples", - "icon": "bell", - "color": "#F2DF0F", "ngModules": [ "myapp.deviceEventsRealTime" ], "js": [ "index.js", - "controllers/deviceEventsRealTimeCtrl.js" + "deviceEventsRealTime.controller.js" ] } diff --git a/plugins/deviceEventsRealTime/deviceEventsRealTime.html b/plugins/deviceEventsRealTime/deviceEventsRealTime.html new file mode 100644 index 0000000..d87a2a6 --- /dev/null +++ b/plugins/deviceEventsRealTime/deviceEventsRealTime.html @@ -0,0 +1,17 @@ +
+
+ No incoming events at the moment... +
+ + + + + +
+ {{e.type}} + + {{e.text || '-- no text message --'}} + Created: {{e.creationTime|date:'medium'}} + Data: {{e | json}} +
+
diff --git a/plugins/deviceEventsRealTime/deviceEventsRealtime.controller.js b/plugins/deviceEventsRealTime/deviceEventsRealtime.controller.js new file mode 100644 index 0000000..1bc55ef --- /dev/null +++ b/plugins/deviceEventsRealTime/deviceEventsRealtime.controller.js @@ -0,0 +1,44 @@ +(function() { + 'use strict'; + + angular.module('myapp.deviceEventsRealTime') + .controller('deviceEventsRealTimeCtrl', DeviceEventsRealTimeController); + + function DeviceEventsRealTimeController($scope, $routeParams, c8yRealtime, c8yAlert) { + var deviceId = $routeParams.deviceId; + var eventsChannel = '/events/' + deviceId; + var SCOPE_ID = $scope.$id; + + function startRealtime() { + c8yRealtime.start(SCOPE_ID, eventsChannel); + } + + function setUpListeners() { + c8yRealtime.addListener(SCOPE_ID, eventsChannel, 'CREATE', onCreateEvent); + c8yRealtime.addListener(SCOPE_ID, eventsChannel, 'DELETE', onDeleteEvent); + } + + function stopRealtime() { + c8yRealtime.stop(SCOPE_ID, eventsChannel); + } + + function onCreateEvent(action, eventObject) { + $scope.events.push(eventObject); + } + + function onDeleteEvent(action, eventObjectId) { + _.remove($scope.events, function (evt) { + return evt.id === eventObjectId; + }); + + c8yAlert.info('Event with id ' + eventObjectId + ' has been deleted.' ); + } + + $scope.events = []; + $scope.$on('$destroy', stopRealtime); + + setUpListeners(); + startRealtime(); + } + +}()); diff --git a/plugins/deviceEventsRealTime/index.js b/plugins/deviceEventsRealTime/index.js index b14fa13..c0e09d8 100644 --- a/plugins/deviceEventsRealTime/index.js +++ b/plugins/deviceEventsRealTime/index.js @@ -1,10 +1,18 @@ -angular.module('myapp.deviceEventsRealTime', []) - .config(['c8yViewsProvider', - function (c8yViewsProvider) { - c8yViewsProvider.when('/device/:deviceId', { - name: 'Real-Time Events', - icon: 'rss', - templateUrl: ':::PLUGIN_PATH:::/views/deviceEventsRealTime.html', - controller: 'deviceEventsRealTimeCtrl' - }); - }]); +(function() { + 'use strict'; + + angular.module('myapp.deviceEventsRealTime', []) + .config(config); + + function config(c8yViewsProvider) { + + c8yViewsProvider.when('/device/:deviceId', { + name: 'Real-Time Events', + icon: 'rss', + templateUrl: ':::PLUGIN_PATH:::/deviceEventsRealTime.html', + controller: 'deviceEventsRealTimeCtrl' + }); + + } + +}()); diff --git a/plugins/deviceEventsRealTime/views/deviceEventsRealTime.html b/plugins/deviceEventsRealTime/views/deviceEventsRealTime.html deleted file mode 100644 index 55246ac..0000000 --- a/plugins/deviceEventsRealTime/views/deviceEventsRealTime.html +++ /dev/null @@ -1,17 +0,0 @@ -
-
- No incoming events at the moment... -
- - - - - -
- {{e.data.type}} - - {{e.data.text || '-- no text message --'}} - - -
-
\ No newline at end of file diff --git a/plugins/myBranding/variables/.DS_Store b/plugins/myBranding/variables/.DS_Store new file mode 100644 index 0000000..5008ddf Binary files /dev/null and b/plugins/myBranding/variables/.DS_Store differ diff --git a/plugins/myplugin/views/index.html b/plugins/myplugin/index.html similarity index 100% rename from plugins/myplugin/views/index.html rename to plugins/myplugin/index.html diff --git a/plugins/myplugin/index.js b/plugins/myplugin/index.js index 9292ed6..cc32dc7 100644 --- a/plugins/myplugin/index.js +++ b/plugins/myplugin/index.js @@ -1,26 +1,33 @@ -//Main module name must be defined in ngModules of the plugin manifest -angular.module('myapp.helloworld', []).config(['c8yNavigatorProvider', 'c8yViewsProvider', -function (c8yNavigatorProvider, c8yViewsProvider) { +(function() { 'use strict'; - c8yNavigatorProvider.addNavigation({ - name: 'New plugin', - icon: 'cube', - priority: 100000, - path: 'hello' - }); + //Main module name must be defined in ngModules of the plugin manifest + //so that they can be loaded at application bootstrap + angular.module('myapp.helloworld', []) + .config(config) + .controller('MyMainController', MainController); - c8yViewsProvider.when('/hello', { - // Please use this string placeholder where you want to refer you plugin path. - templateUrl: ':::PLUGIN_PATH:::/views/index.html', - controller: 'mh_MainCtrl' - }); + function config(c8yNavigatorProvider, c8yViewsProvider) { + c8yNavigatorProvider.addNavigation({ + name: 'New plugin', + icon: 'cube', + priority: 100000, + path: 'hello' + }); -}]); + c8yViewsProvider.when('/hello', { + // Please use this string placeholder where you want to refer you plugin path. + templateUrl: ':::PLUGIN_PATH:::/index.html', + controller: 'MyMainController' + }); -angular.module('myapp.helloworld').controller('mh_MainCtrl', ['$scope', function ($scope) { - 'use strict'; + c8yViewsProvider.when('/', { + redirectTo: '/hello' + }); + } - $scope.hello = 'Hello world!'; + function MainController($scope) { + $scope.hello = 'Hello world!'; + } -}]); \ No newline at end of file +}());