├── demo_2_ui
├── __init__.py
├── resources
│ ├── index.html
│ └── module.es
├── plugin.yml
└── main.py
├── demo_3_bower
├── __init__.py
├── bower.json
├── resources
│ ├── js
│ │ ├── module.coffee
│ │ ├── routing.coffee
│ │ └── controllers
│ │ │ └── index.controller.coffee
│ └── partial
│ │ └── index.html
├── main.py
└── plugin.yml
├── demo_5_widget
├── __init__.py
├── resources
│ ├── js
│ │ ├── module.coffee
│ │ └── controllers
│ │ │ └── widget.controller.coffee
│ └── partial
│ │ ├── widget.html
│ │ └── widget.config.html
├── plugin.yml
└── widget.py
├── demo_1_minimal
├── main.py
├── __init__.py
└── plugin.yml
├── demo_4_http
├── __init__.py
├── resources
│ ├── js
│ │ ├── module.coffee
│ │ ├── routing.coffee
│ │ └── controllers
│ │ │ └── index.controller.coffee
│ └── partial
│ │ └── index.html
├── plugin.yml
├── main.py
└── views.py
├── .gitignore
└── README.md
/demo_2_ui/__init__.py:
--------------------------------------------------------------------------------
1 | from .main import *
2 |
--------------------------------------------------------------------------------
/demo_3_bower/__init__.py:
--------------------------------------------------------------------------------
1 | from .main import *
2 |
--------------------------------------------------------------------------------
/demo_5_widget/__init__.py:
--------------------------------------------------------------------------------
1 | from .widget import *
2 |
--------------------------------------------------------------------------------
/demo_1_minimal/main.py:
--------------------------------------------------------------------------------
1 | import logging
2 |
3 | logging.info('Demo plugin loaded!')
--------------------------------------------------------------------------------
/demo_4_http/__init__.py:
--------------------------------------------------------------------------------
1 | from .main import *
2 | # note the extra module
3 | from .views import *
--------------------------------------------------------------------------------
/demo_4_http/resources/js/module.coffee:
--------------------------------------------------------------------------------
1 | angular.module 'ajenti.demo4', [
2 | 'core',
3 | ]
4 |
5 |
--------------------------------------------------------------------------------
/demo_1_minimal/__init__.py:
--------------------------------------------------------------------------------
1 | # This file gets imported by the core during plugin loading phase
2 | from .main import *
3 |
--------------------------------------------------------------------------------
/demo_5_widget/resources/js/module.coffee:
--------------------------------------------------------------------------------
1 | angular.module 'ajenti.demo5', [
2 | 'core',
3 | 'ajenti.dashboard',
4 | ]
5 |
6 |
--------------------------------------------------------------------------------
/demo_3_bower/bower.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "plugin",
3 | "private": true,
4 | "dependencies": {
5 | "angular-chart.js": "~0.5.3"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/demo_2_ui/resources/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/demo_3_bower/resources/js/module.coffee:
--------------------------------------------------------------------------------
1 | angular.module 'ajenti.demo3', [
2 | # Note that we reference our Bower module
3 | 'core',
4 | 'chart.js',
5 | ]
6 |
7 |
--------------------------------------------------------------------------------
/demo_3_bower/resources/partial/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
--------------------------------------------------------------------------------
/demo_5_widget/resources/partial/widget.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 | {{value || 'Unknown'}}
7 |
8 |
9 |
--------------------------------------------------------------------------------
/demo_3_bower/resources/js/routing.coffee:
--------------------------------------------------------------------------------
1 | angular.module('ajenti.demo3').config ($routeProvider) ->
2 | $routeProvider.when '/view/demo3',
3 | templateUrl: '/demo_3_bower:resources/partial/index.html'
4 | controller: 'Demo3IndexController'
5 |
--------------------------------------------------------------------------------
/demo_4_http/resources/js/routing.coffee:
--------------------------------------------------------------------------------
1 | angular.module('ajenti.demo4').config ($routeProvider) ->
2 | $routeProvider.when '/view/demo4',
3 | templateUrl: '/demo_4_http:resources/partial/index.html'
4 | controller: 'Demo4IndexController'
5 |
--------------------------------------------------------------------------------
/demo_5_widget/resources/partial/widget.config.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/demo_1_minimal/plugin.yml:
--------------------------------------------------------------------------------
1 | # This file describes the plugin
2 | name: demo_1_minimal
3 | author: Ajenti project
4 | email: e@ajenti.org
5 | url: http://ajenti.org
6 | version: '0.1'
7 | title: 'Demo 1 (minimal)'
8 | icon: question
9 | # add a dependency on the 'core' plugin (not really required in the minimal example)
10 | dependencies:
11 | - !PluginDependency {
12 | plugin_name: core
13 | }
14 | resources: []
15 |
--------------------------------------------------------------------------------
/demo_4_http/plugin.yml:
--------------------------------------------------------------------------------
1 | name: demo_4_http
2 | author: Ajenti project
3 | email: e@ajenti.org
4 | url: http://ajenti.org
5 | version: '0.1'
6 | title: 'Demo 4 (HTTP)'
7 | icon: question
8 | dependencies:
9 | - !PluginDependency {
10 | plugin_name: core
11 | }
12 | resources:
13 | - 'resources/js/module.coffee'
14 | - 'resources/js/routing.coffee'
15 | - 'resources/js/controllers/index.controller.coffee'
16 | - 'resources/partial/index.html'
17 | - 'ng:ajenti.demo4'
18 |
--------------------------------------------------------------------------------
/demo_4_http/resources/js/controllers/index.controller.coffee:
--------------------------------------------------------------------------------
1 | angular.module('ajenti.demo4').controller 'Demo4IndexController', ($scope, $http, notify, pageTitle) ->
2 | pageTitle.set('Demo: HTTP')
3 |
4 | $scope.a = 8
5 | $scope.b = 3
6 |
7 | $scope.run = (method) ->
8 | $http.get("/api/demo4/calculate/#{method}/#{$scope.a}/#{$scope.b}").success (data) ->
9 | $scope.result = data
10 | .error (err) ->
11 | notify.error 'Calculation failed', err.message
12 | $scope.result = null
13 |
--------------------------------------------------------------------------------
/demo_2_ui/plugin.yml:
--------------------------------------------------------------------------------
1 | # This file describes the plugin
2 | name: demo_2_ui
3 | author: Ajenti project
4 | email: e@ajenti.org
5 | url: http://ajenti.org
6 | version: '0.1'
7 | title: 'Demo 2 (UI)'
8 | icon: question
9 | # dependency on Core is required for UI plugins
10 | dependencies:
11 | - !PluginDependency {
12 | plugin_name: core
13 | }
14 | resources:
15 | - 'resources/module.es' # angular module
16 | - 'resources/index.html' # view template
17 | - 'ng:ajenti.demo2' # instructs ajenti to load Angular module 'ajenti.demo2'
18 |
--------------------------------------------------------------------------------
/demo_5_widget/resources/js/controllers/widget.controller.coffee:
--------------------------------------------------------------------------------
1 | angular.module('ajenti.demo5').controller 'Demo5WidgetController', ($scope) ->
2 | # $scope.widget is our widget descriptor here
3 | $scope.$on 'widget-update', ($event, id, data) ->
4 | if id != $scope.widget.id
5 | return
6 | $scope.value = data
7 |
8 |
9 | angular.module('ajenti.demo5').controller 'Demo5WidgetConfigController', ($scope) ->
10 | # $scope.configuredWidget is our widget descriptor here
11 | $scope.configuredWidget.config.bytes ?= 4
12 |
--------------------------------------------------------------------------------
/demo_5_widget/plugin.yml:
--------------------------------------------------------------------------------
1 | name: demo_5_widget
2 | author: Ajenti project
3 | email: e@ajenti.org
4 | url: http://ajenti.org
5 | version: '0.1'
6 | title: 'Demo 5 (Widget)'
7 | icon: question
8 | dependencies:
9 | - !PluginDependency {
10 | plugin_name: core
11 | }
12 | - !PluginDependency {
13 | plugin_name: dashboard
14 | }
15 | resources:
16 | - 'resources/js/module.coffee'
17 | - 'resources/js/controllers/widget.controller.coffee'
18 | - 'resources/partial/widget.html'
19 | - 'resources/partial/widget.config.html'
20 | - 'ng:ajenti.demo5'
21 |
--------------------------------------------------------------------------------
/demo_4_http/main.py:
--------------------------------------------------------------------------------
1 | from jadi import component
2 |
3 | from aj.plugins.core.api.sidebar import SidebarItemProvider
4 |
5 |
6 | @component(SidebarItemProvider)
7 | class ItemProvider(SidebarItemProvider):
8 | def __init__(self, context):
9 | pass
10 |
11 | def provide(self):
12 | return [
13 | {
14 | # attach the item to the 'general' category
15 | 'attach': 'category:general',
16 | 'name': 'Demo: HTTP',
17 | 'icon': 'question',
18 | 'url': '/view/demo4',
19 | 'children': []
20 | }
21 | ]
22 |
--------------------------------------------------------------------------------
/demo_2_ui/resources/module.es:
--------------------------------------------------------------------------------
1 | // the module should depend on 'core' to use the stock Angular components
2 | angular.module('ajenti.demo2', [
3 | 'core',
4 | ]);
5 |
6 | angular.module('ajenti.demo2').config(($routeProvider) => {
7 | $routeProvider.when('/view/demo2', {
8 | templateUrl: '/demo_2_ui:resources/index.html',
9 | controller: 'Demo2IndexController',
10 | });
11 | });
12 |
13 | angular.module('ajenti.demo2').controller('Demo2IndexController', ($scope, notify, pageTitle) => {
14 | pageTitle.set('Demo: UI');
15 |
16 | $scope.counter = 0;
17 |
18 | $scope.click = () => {
19 | $scope.counter += 1;
20 | notify.info('+1');
21 | }
22 | });
23 |
--------------------------------------------------------------------------------
/demo_2_ui/main.py:
--------------------------------------------------------------------------------
1 | from jadi import component
2 |
3 | from aj.plugins.core.api.sidebar import SidebarItemProvider
4 |
5 |
6 | @component(SidebarItemProvider)
7 | class ItemProvider(SidebarItemProvider):
8 | '''
9 | To add a sidebar item, we create a component implementing SidebarItemProvider
10 | '''
11 | def __init__(self, context):
12 | pass
13 |
14 | def provide(self):
15 | return [
16 | {
17 | # attach the item to the 'general' category
18 | 'attach': 'category:general',
19 | 'name': 'Demo: UI',
20 | 'icon': 'question',
21 | 'url': '/view/demo2',
22 | 'children': []
23 | }
24 | ]
25 |
--------------------------------------------------------------------------------
/demo_3_bower/main.py:
--------------------------------------------------------------------------------
1 | from jadi import component
2 |
3 | from aj.plugins.core.api.sidebar import SidebarItemProvider
4 |
5 |
6 | @component(SidebarItemProvider)
7 | class ItemProvider(SidebarItemProvider):
8 | '''
9 | To add a sidebar item, we create a component implementing SidebarItemProvider
10 | '''
11 | def __init__(self, context):
12 | pass
13 |
14 | def provide(self):
15 | return [
16 | {
17 | # attach the item to the 'general' category
18 | 'attach': 'category:general',
19 | 'name': 'Demo: Bower',
20 | 'icon': 'question',
21 | 'url': '/view/demo3',
22 | 'children': []
23 | }
24 | ]
25 |
--------------------------------------------------------------------------------
/demo_3_bower/plugin.yml:
--------------------------------------------------------------------------------
1 | name: demo_3_bower
2 | author: Ajenti project
3 | email: e@ajenti.org
4 | url: http://ajenti.org
5 | version: '0.1'
6 | title: 'Demo 3 (Bower)'
7 | icon: question
8 | dependencies:
9 | - !PluginDependency {
10 | plugin_name: core
11 | }
12 | resources:
13 | # it's important to include the required Bower resources here
14 | - 'resources/vendor/Chart.js/Chart.min.js'
15 | - 'resources/vendor/angular-chart.js/dist/angular-chart.min.js'
16 | - 'resources/vendor/angular-chart.js/dist/angular-chart.css'
17 | - 'resources/js/module.coffee'
18 | - 'resources/js/routing.coffee'
19 | - 'resources/js/controllers/index.controller.coffee'
20 | - 'resources/partial/index.html'
21 | - 'ng:ajenti.demo3'
22 |
--------------------------------------------------------------------------------
/demo_5_widget/widget.py:
--------------------------------------------------------------------------------
1 | import os
2 | from jadi import component
3 |
4 | from aj.plugins.dashboard.api import Widget
5 |
6 |
7 | @component(Widget)
8 | class RandomWidget(Widget):
9 | id = 'random'
10 |
11 | # display name
12 | name = 'Random'
13 |
14 | # template of the widget
15 | template = '/demo_5_widget:resources/partial/widget.html'
16 |
17 | # template of the configuration dialog
18 | config_template = '/demo_5_widget:resources/partial/widget.config.html'
19 |
20 | def __init__(self, context):
21 | Widget.__init__(self, context)
22 |
23 | def get_value(self, config):
24 | if 'bytes' not in config:
25 | return 'Not configured'
26 | return os.urandom(int(config['bytes'])).encode('hex')
27 |
--------------------------------------------------------------------------------
/demo_3_bower/resources/js/controllers/index.controller.coffee:
--------------------------------------------------------------------------------
1 | angular.module('ajenti.demo3').controller 'Demo3IndexController', ($scope, $interval, pageTitle) ->
2 | pageTitle.set('Demo: Bower')
3 |
4 | $scope.labels = ["January", "February", "March", "April", "May", "June", "July"]
5 | $scope.series = ['Series A', 'Series B']
6 | $scope.dataTemplate = [
7 | [65, 59, 80, 81, 56, 55, 40],
8 | [28, 48, 40, 19, 86, 27, 90]
9 | ]
10 |
11 | interval = $interval () ->
12 | $scope.data = [[], []]
13 | for i in [0...2]
14 | for j in [0...7]
15 | $scope.data[i].push $scope.dataTemplate[i][j] + Math.random() * 5
16 | , 250
17 |
18 | $scope.$on '$destroy', () ->
19 | $interval.cancel(interval)
--------------------------------------------------------------------------------
/demo_4_http/resources/partial/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | = {{result.value}}
23 |
24 |
25 | Calculated in {{result.time|time:10}}
26 |
27 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | vendor
3 |
4 | # Byte-compiled / optimized / DLL files
5 | __pycache__/
6 | *.py[cod]
7 |
8 | # C extensions
9 | *.so
10 |
11 | # Distribution / packaging
12 | .Python
13 | env/
14 | build/
15 | develop-eggs/
16 | dist/
17 | downloads/
18 | eggs/
19 | lib/
20 | lib64/
21 | parts/
22 | sdist/
23 | var/
24 | *.egg-info/
25 | .installed.cfg
26 | *.egg
27 |
28 | # PyInstaller
29 | # Usually these files are written by a python script from a template
30 | # before PyInstaller builds the exe, so as to inject date/other infos into it.
31 | *.manifest
32 | *.spec
33 |
34 | # Installer logs
35 | pip-log.txt
36 | pip-delete-this-directory.txt
37 |
38 | # Unit test / coverage reports
39 | htmlcov/
40 | .tox/
41 | .coverage
42 | .cache
43 | nosetests.xml
44 | coverage.xml
45 |
46 | # Translations
47 | *.mo
48 | *.pot
49 |
50 | # Django stuff:
51 | *.log
52 |
53 | # Sphinx documentation
54 | docs/_build/
55 |
56 | # PyBuilder
57 | target/
58 |
--------------------------------------------------------------------------------
/demo_4_http/views.py:
--------------------------------------------------------------------------------
1 | import time
2 | from jadi import component
3 |
4 | from aj.api.http import url, HttpPlugin
5 |
6 | from aj.api.endpoint import endpoint, EndpointError, EndpointReturn
7 |
8 |
9 | @component(HttpPlugin)
10 | class Handler(HttpPlugin):
11 | def __init__(self, context):
12 | self.context = context
13 |
14 | @url(r'/api/demo4/calculate/(?P\w+)/(?P\d+)/(?P\d+)')
15 | @endpoint(api=True)
16 | def handle_api_calculate(self, http_context, operation=None, a=None, b=None):
17 | start_time = time.time()
18 |
19 | try:
20 | if operation == 'add':
21 | result = int(a) + int(b)
22 | elif operation == 'divide':
23 | result = int(a) / int(b)
24 | else:
25 | raise EndpointReturn(404)
26 | except ZeroDivisionError:
27 | raise EndpointError('Division by zero')
28 |
29 | return {
30 | 'value': result,
31 | 'time': time.time() - start_time
32 | }
33 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Ajenti demo plugins
2 | ===================
3 |
4 | This repository contains simple commented examples of Ajenti plugins.
5 |
6 | Quickstart:
7 |
8 | ```
9 | git clone https://github.com/ajenti/demo-plugins.git
10 | cd demo-plugins
11 |
12 | sudo npm install -g babel babel-preset-es2015 less bower
13 | sudo pip install ajenti-panel ajenti-dev-multitool ajenti.plugin.core
14 | ajenti-dev-multitool --bower install
15 | ajenti-dev-multitool --build
16 |
17 | sudo ajenti-panel -v --autologin --stock-plugins --plugins .
18 | ```
19 |
20 | Demo 1: minimal
21 | ---------------
22 |
23 | A super-minimal example of a plugin. Prints an info message to log.
24 |
25 | - [__init__.py](https://github.com/ajenti/demo-plugins/blob/master/demo_1_minimal/__init__.py#L2)
26 | - [plugin.yml](https://github.com/ajenti/demo-plugins/blob/master/demo_1_minimal/plugin.yml)
27 |
28 | Demo 2: UI
29 | ----------
30 |
31 | A minimal UI example showing a page and some Angular.JS interaction
32 |
33 | - [dependencies & resources](https://github.com/ajenti/demo-plugins/blob/master/demo_2_ui/plugin.yml#L10)
34 | - [sidebar item](https://github.com/ajenti/demo-plugins/blob/master/demo_2_ui/main.py#L6)
35 | - [JS code](https://github.com/ajenti/demo-plugins/blob/master/demo_2_ui/resources/module.es)
36 | - [view template](https://github.com/ajenti/demo-plugins/blob/master/demo_2_ui/resources/index.html)
37 |
38 | Demo 3: Bower
39 | -------------
40 |
41 | Example of a plugin that includes a Bower component (Chart.JS).
42 |
43 | Before running, download the component (not included): ``ajenti-dev-multitool --bower install``
44 |
45 | - [bower.json](https://github.com/ajenti/demo-plugins/blob/master/demo_3_bower/bower.json)
46 | - [including Bower files](https://github.com/ajenti/demo-plugins/blob/master/demo_3_bower/plugin.yml#L13)
47 | - [angular.js module dependency](https://github.com/ajenti/demo-plugins/blob/master/demo_3_bower/resources/js/module.coffee#L4)
48 |
49 | Demo 4: HTTP
50 | ------------
51 |
52 | Example of how one can add custom backend API methods
53 |
54 | - [API views](https://github.com/ajenti/demo-plugins/blob/master/demo_4_http/views.py)
55 | - [client code](https://github.com/ajenti/demo-plugins/blob/master/demo_4_http/resources/js/controllers/index.controller.coffee#L8)
56 |
57 | Demo 5: Dashboard Widget
58 | ------------------------
59 |
60 | - [widget backend code](https://github.com/ajenti/demo-plugins/blob/master/demo_5_widget/widget.py)
61 | - [widget template](https://github.com/ajenti/demo-plugins/blob/master/demo_5_widget/resources/partial/widget.html)
62 | - [widget conf dialog template](https://github.com/ajenti/demo-plugins/blob/master/demo_5_widget/resources/partial/widget.config.html)
63 | - [controllers](https://github.com/ajenti/demo-plugins/blob/master/demo_5_widget/resources/js/controllers/widget.controller.coffee)
64 |
--------------------------------------------------------------------------------