mirror of
https://github.com/mkschreder/juci.git
synced 2025-01-08 11:57:39 +08:00
docs: update documentation
This commit is contained in:
parent
868805f26c
commit
f7a2e530c5
@ -1,45 +0,0 @@
|
||||
# JUCI addons
|
||||
|
||||
JUCI itself is only 12 javascript files. Most of the functionality in JUCI comes from plugins.
|
||||
|
||||
So how do you create plugins?
|
||||
|
||||
JUCI makes it very easy to create addons. The easies way to add a new modules is to create a folder in the plugins directory that has this structure:
|
||||
|
||||
plugins/
|
||||
new-module
|
||||
src
|
||||
pages
|
||||
widgets
|
||||
somemainfile.js
|
||||
backend
|
||||
.. backend scripts go here
|
||||
Makefile
|
||||
access.json
|
||||
menu.json
|
||||
|
||||
You should keep this structure same for now because juci right now relies on plugin code to be structured this way.
|
||||
|
||||
# the Makefile
|
||||
|
||||
Even if you don't put anything in the Makefile, just will use default settings and scan src/{pages,widgets} folders for html and js files. But if you still want to have greater control of what is included then you can manually add your source files to build process by defining a section called Plugin/<yourpluginfoldername> and then alter one of these fields:
|
||||
|
||||
define Plugin/<somename>
|
||||
CODE_LOAD:=<num> - this specifies loading order. It is sometimes important to control load order. Default is 50. Juci core has this set to 01 to load juci before any other modules.
|
||||
STYLE_LOAD:=<num> - this is the same for styles
|
||||
TPL_LOAD:=<num> - this is for templates (html). If you load your templates AFTER another module then you can basically override any template in any preceding module by simply creating file with the same name.
|
||||
JAVASCRIPT-y:=<javascript files> - specify your js files
|
||||
STYLES-y:=<css> - specify styles
|
||||
TEMPLATES-y:=<html> specify html templates
|
||||
endef
|
||||
|
||||
You can also create an install hook in case you need to install any extra files to the root when make install command is run.
|
||||
|
||||
define Plugin/<yourplugin>/install
|
||||
PLUGIN_DIR - this variable is set by juci to current plugin directory (absolute path)
|
||||
CP - set to command used for copying files
|
||||
INSTALL_DIR - set to command for installing directories
|
||||
$(1) is install destination
|
||||
endef
|
||||
|
||||
|
@ -1,35 +0,0 @@
|
||||
# the $ethernet factory
|
||||
|
||||
This is an object for managing layer2 ethernet devices. This includes all
|
||||
devices that are reported by "ip" command on linux and this includes ADSL,
|
||||
VDSL, VLAN and various ethernet devices. This module does NOT manage ip level
|
||||
settings though - that job should be left to the $network module.
|
||||
|
||||
## functionality
|
||||
|
||||
method: getAdapters - return: promise, callback(list:ethernet_adapter)
|
||||
|
||||
returns list of all ethernet adapters that are configurable on the
|
||||
system. This includes adapters that are currently down or for some
|
||||
reason not currently present on the system. This function will query
|
||||
all available adapters through the ip command and then let all
|
||||
subsystems fill in their own details for each item in the list before
|
||||
returning the list. This is done by running the list through all
|
||||
registered layer2 subsystems which are configurable through the gui.
|
||||
|
||||
object: ethernet_adapter
|
||||
|
||||
This is a structure returned by the above method.
|
||||
|
||||
.name: identified name of the adapter.
|
||||
for wireless adapters this could be the ssid. For ports this would
|
||||
be LAN1 or WAN etc. The name should be filled in by the subsystem
|
||||
responsible for managing the adapter.
|
||||
|
||||
.id: ethernet device name.
|
||||
|
||||
.subsystem: name of the subsystem managing the adapter.
|
||||
|
||||
.config: uci configuration for the given adapter.
|
||||
This can point to subsystem specific configuration for the adapter.
|
||||
|
@ -1,43 +0,0 @@
|
||||
# JUCI file system structure
|
||||
|
||||
To make development more straightforward and in order to faciliate easy
|
||||
searching and editing of files, juci follows a certain set of rules with
|
||||
regards to file names.
|
||||
|
||||
* all pages must have the same filename as the URL hasbang identifying the
|
||||
page.
|
||||
|
||||
WHY: so that you can look at url ex. #!internet-dns and know that this page
|
||||
is in file internet-dns.[html|js] (or old style internet.dns.[html|js]).
|
||||
|
||||
* all page files must be globally unique across all plugins.
|
||||
|
||||
WHY: so that you can easily override pages from other plugins. Even if the
|
||||
files did not have unique names, you would still need to have unique
|
||||
controllers and directives across ALL plugins that are in use. Therefore this
|
||||
does not in any way limit you. It is a good thing that allows you to for
|
||||
instance override default page or widget in a juci theme.
|
||||
|
||||
* all widget files must be globally unique for all widgets across all plugins.
|
||||
|
||||
WHY: same as for pages. You can't have two html tags with same name in angular
|
||||
anyway. You can still override files though.
|
||||
|
||||
* all widget filenames should have a name that reflects the name of the
|
||||
directive and the controller for the widget. Keep in mind that angular
|
||||
directive name is in "camelCase" while the resulting html tag is in
|
||||
"camel-case" with a dash in between where a capital letter is placed in the
|
||||
directive.
|
||||
|
||||
WHY: because it makes it very easy to navigate a tree of files and right
|
||||
away go to the file where the widget is implemented. In vim this is a matter of
|
||||
simply using text search function inside a NERDTree window - but even in geany
|
||||
TreeViewer it is easy to visually find the file that contains html widget code.
|
||||
And since names are globally unique, you will only have a file with that name
|
||||
in a single place. When you then change names of your directive/controller, it
|
||||
is a good idea to also change the name of the file.
|
||||
|
||||
* all lua script objects should have the same filename as the object on ubus.
|
||||
|
||||
Well actually, ubus-scriptd will take care of that.
|
||||
|
90
docs/juci-structure.md
Normal file
90
docs/juci-structure.md
Normal file
@ -0,0 +1,90 @@
|
||||
# JUCI file system structure
|
||||
|
||||
To make development more straightforward and in order to faciliate easy
|
||||
searching and editing of files, juci follows a certain set of rules with
|
||||
regards to file names.
|
||||
|
||||
PLUGINS
|
||||
=======
|
||||
|
||||
The easiest way to build plugins in juci is to simply include them into the juci plugin tree and they will be built automatically (of course provided that you have selected the plugin in Makefile.local or in the make environment above that builds juci). All plugins in juci follow a standard directory structure. This allows all plugins to be built using the same makefile. You can however add your own custom makefile with custom commands that you want to execute during the build.
|
||||
|
||||
plugins/
|
||||
|-- yourplugin-unique-name/
|
||||
|-- src/
|
||||
|-- pages/
|
||||
|-- widgets/
|
||||
|-- some_general_js_code.js
|
||||
|-- Makefile
|
||||
|-- access.json
|
||||
|
||||
THEMES
|
||||
======
|
||||
|
||||
At the buildsystem level juci does not differentiate between plugins and themes. So the same directory structure that is used for plugins will also work for themes.
|
||||
|
||||
MAKEFILE
|
||||
========
|
||||
|
||||
Even if you don't put anything in the Makefile, just will use default settings and scan src/{pages,widgets} folders for html and js files. But if you still want to have greater control of what is included then you can manually add your source files to build process by defining a section called Plugin/<yourpluginfoldername> and then alter one of these fields:
|
||||
|
||||
define Plugin/<somename>
|
||||
CODE_LOAD:=<num> - this specifies loading order. It is sometimes important to control load order. Default is 50. Juci core has this set to 01 to load juci before any other modules.
|
||||
STYLE_LOAD:=<num> - this is the same for styles
|
||||
TPL_LOAD:=<num> - this is for templates (html). If you load your templates AFTER another module then you can basically override any template in any preceding module by simply creating file with the same name.
|
||||
JAVASCRIPT-y:=<javascript files> - specify your js files
|
||||
STYLES-y:=<css> - specify styles
|
||||
TEMPLATES-y:=<html> specify html templates
|
||||
endef
|
||||
|
||||
You can also create an install hook in case you need to install any extra files to the root when make install command is run.
|
||||
|
||||
define Plugin/<yourplugin>/install
|
||||
PLUGIN_DIR - this variable is set by juci to current plugin directory (absolute path)
|
||||
CP - set to command used for copying files
|
||||
INSTALL_DIR - set to command for installing directories
|
||||
$(1) is install destination
|
||||
endef
|
||||
|
||||
|
||||
RULES
|
||||
=====
|
||||
|
||||
* all pages must have the same filename as the URL hasbang identifying the
|
||||
page.
|
||||
|
||||
`WHY`: so that you can look at url ex. #!internet-dns and know that this page
|
||||
is in file internet-dns.[html|js] (or old style internet.dns.[html|js]).
|
||||
|
||||
* all page files must be globally unique across all plugins.
|
||||
|
||||
`WHY`: so that you can easily override pages from other plugins. Even if the
|
||||
files did not have unique names, you would still need to have unique
|
||||
controllers and directives across ALL plugins that are in use. Therefore this
|
||||
does not in any way limit you. It is a good thing that allows you to for
|
||||
instance override default page or widget in a juci theme.
|
||||
|
||||
* all widget files must be globally unique for all widgets across all plugins.
|
||||
|
||||
`WHY`: same as for pages. You can't have two html tags with same name in angular
|
||||
anyway. You can still override files though.
|
||||
|
||||
* all widget filenames should have a name that reflects the name of the
|
||||
directive and the controller for the widget.
|
||||
|
||||
Keep in mind that angular directive name is in "camelCase" while the
|
||||
resulting html tag is in "camel-case" with a dash in between where a capital
|
||||
letter is placed in the directive.
|
||||
|
||||
`WHY`: because it makes it very easy to navigate a tree of files and right
|
||||
away go to the file where the widget is implemented. In vim this is a matter of
|
||||
simply using text search function inside a NERDTree window - but even in geany
|
||||
TreeViewer it is easy to visually find the file that contains html widget code.
|
||||
And since names are globally unique, you will only have a file with that name
|
||||
in a single place. When you then change names of your directive/controller, it
|
||||
is a good idea to also change the name of the file.
|
||||
|
||||
* all lua script objects should have the same filename as the object on ubus.
|
||||
|
||||
Well actually, ubus-scriptd will take care of that.
|
||||
|
17
docs/juci.md
17
docs/juci.md
@ -3,8 +3,22 @@ JUCI
|
||||
|
||||
JUCI WebGUI is designed for building modern and dynamic web interfaces for embedded devices.
|
||||
|
||||
CORE SUBSYTEMS
|
||||
==============
|
||||
|
||||
* [$rpc](rpc.html) - JUCI rpc subsystem for making remote calls to the server
|
||||
* [$uci](uci.html) - JUCI uci subsystem for managing configuration options in uci on the server
|
||||
* [$ethernet](ethernet.html) - get information about low level devices
|
||||
* [$network](network.html) - get information about ip network and clients connected to it
|
||||
* [$wireless](wireless.html) - get information about wireless clients and wireless devices
|
||||
|
||||
TUTORIALS
|
||||
=========
|
||||
|
||||
* [Creating Pages](creating-pages.html) - learn how to setup a new page in juci plugin
|
||||
|
||||
CORE OBJECTS
|
||||
------------
|
||||
============
|
||||
|
||||
The core system of juci is very small. In fact, it is there basically to provide a simple startup code and to bind all other parts together. JUCI is built almost entirely using angular.js and all components are tied together mostly through angular. The core codebase merely provides ways for juci to make RPC calls to the backend and manipulate configuration settings in UCI. The core is located in /juci/src/js/ folder of the source tree.
|
||||
|
||||
@ -53,3 +67,4 @@ JUCI language and translation system. This is really just a simple wrapper to ma
|
||||
# juci/src/js/uci.js
|
||||
|
||||
The juci UCI subsystem. Together with juci RPC this system allows to easily handle uci data by providing a convenient getter/setter based interface to uci objects so that values can easily be set inside the browser and then sync-ed automatically to the server with only changed values being sent over the wire.
|
||||
|
||||
|
9
docs/wireless.md
Normal file
9
docs/wireless.md
Normal file
@ -0,0 +1,9 @@
|
||||
JUCI WIRELESS SUBSYSTEM
|
||||
=======================
|
||||
|
||||
TODO
|
||||
|
||||
METHODS
|
||||
-------
|
||||
|
||||
|
36
juci/docs/creating-pages.md
Normal file
36
juci/docs/creating-pages.md
Normal file
@ -0,0 +1,36 @@
|
||||
CREATING PAGES AND WIDGETS
|
||||
==============
|
||||
|
||||
A JUCI based interface is typically built from a number of pages that are accessible through a navigation menu and where each page can consist of unlimited number of widgets that build up the page. Thus pages are relatively static components that you refer to from your theme's menu.json file, while widgets are reusable components that can appear in any number of pages. Widgets are typically refered (or included) into a page by means of using the directive(1) of a widget. In JUCI all widgets should have the same filename as the name of the directive that they implement.
|
||||
|
||||
CREATING A PAGE
|
||||
===============
|
||||
|
||||
Create two files in plugins/your_plugin/src/pages/ directory and give them a descriptive (and globally unique name):
|
||||
|
||||
|--pages/
|
||||
|----yourplugin-page-main.js
|
||||
|----yourplugin-page-main.html
|
||||
|
||||
Now you will create an angular controller and a template for your page. Pages typically directly refer to their controller in the page html using ng-controller tag. This is mainly an artifact from when this system was created.
|
||||
|
||||
yourplugin-page-main.js:
|
||||
|
||||
JUCI.app.controller("yourpluginPageMain", function($scope, $rpc, $uci){
|
||||
$rpc.juci.system.info().done(function(info){
|
||||
$scope.text = JSON.stringify(info);
|
||||
$scope.$apply();
|
||||
});
|
||||
});
|
||||
|
||||
yourplugin-page-main.html:
|
||||
|
||||
<juci-layout-single-column>
|
||||
<div ng-controller="yourpluginPageMain">
|
||||
<pre>{{text}}</pre>
|
||||
</div>
|
||||
</juci-layout-single-column>
|
||||
|
||||
Here we create a page with single column layout (in reality layout-single-column is in fact a juci widget that you can use to setup this kind of layout) and then we add code to make a ubus call to rpc function located in /usr/lib/ubus/juci/system. The result is placed inside a scope variable called *text* and then the view is updated using $scope.$apply(); Note that you only need to do $scope.$apply() here because this is an asynchronous method call. In the main controller function you do not need to call apply() in order to make changes visible - but when result is only available at some later point in time after your code has already exited your controller function then you do need to call $apply() manually.
|
||||
|
||||
If you now build juci (after adding CONFIG_PACKAGE_yourplugin=y to Makefile.local) and go to page http://juci/#!/yourplugin-page-main then you should be able to see a JSON representation of the result from the ubus call to get system info.
|
@ -1,4 +1,5 @@
|
||||
# $rpc factory
|
||||
JUCI $rpc SUBSYSTEM
|
||||
===================
|
||||
|
||||
This factory provides access to the rpc subsystem on OpenWRT through
|
||||
uhttpd-mod-ubus plugin. In juci, all dynamic data requests are done through
|
||||
@ -6,14 +7,14 @@ json rpc. So most plugins will use this module to communicate with the backend.
|
||||
|
||||
The rpc module is available in two ways:
|
||||
|
||||
* angular $rpc factory / service
|
||||
* $rpc variable in the browser window object (you can access it like that in
|
||||
* angular $rpc factory / service
|
||||
* $rpc variable in the browser window object (you can access it like that in
|
||||
browser console)
|
||||
|
||||
For the most part you will be using the angular service for doing rpc calls
|
||||
because most of juci plugins are angular objects.
|
||||
|
||||
### accessing $rpc in angular
|
||||
`accessing $rpc in angular`
|
||||
|
||||
JUCI.app.controller("yourController", function($rpc){
|
||||
$rpc.juci.ui.menu().done(function(){
|
||||
@ -21,7 +22,7 @@ because most of juci plugins are angular objects.
|
||||
});
|
||||
});
|
||||
|
||||
### accessing in window
|
||||
`accessing in window`
|
||||
|
||||
$rpc.juci.ui.menu().done(function(){
|
||||
|
||||
@ -42,7 +43,8 @@ access.json file and then install it with unique name into
|
||||
/usr/share/rpcd/acl.d/ folder on the router. Exactly how to configure acl lists
|
||||
is described in more detail in OpenWRT rpcd documentation.
|
||||
|
||||
## rpc object methods
|
||||
METHODS
|
||||
=======
|
||||
|
||||
$sid: function(sid) -> sid
|
||||
Set or get current session id for currently active session
|
||||
@ -72,18 +74,19 @@ is described in more detail in OpenWRT rpcd documentation.
|
||||
in using current version of rpcd. In the future this may change to
|
||||
include only the methods availabel through unauthenticated session.
|
||||
|
||||
## building the backend
|
||||
BACKEND
|
||||
=======
|
||||
|
||||
JUCI backend can be any kind of ubus plugin, but juci itself uses lua plugins
|
||||
that are loaded by the main juci rpcd module. This allows you to write the juci
|
||||
backend in any scripting language that you like (which of course needs to be
|
||||
present on the router). JUCI prefers to use lua for backend scripting though.
|
||||
In order for RPC calls to work, you obviously need a backend that will execute
|
||||
the call on the actual device. JUCI supports writing backend in any language
|
||||
that can publish objects on ubus and it also provides support for writing ubus
|
||||
objects in shell scripts. So you have a very wide choice in how exactly you
|
||||
will implement your backend. JUCI is for the most part now using Lua to
|
||||
implement backend functions because it has proven to be dynamic enough and also
|
||||
fast on actual hardware.
|
||||
|
||||
## communicating with the backend
|
||||
|
||||
Once your backend is accessible on ubus and you have configured uhttpd to allow
|
||||
you access to it's ubus methods, you can use the $rpc object to access your
|
||||
method just as though it would have been any javascript method.
|
||||
Once your backend publishes it's rpc functions on ubus, they will automatically
|
||||
become available in juci $rpc object once you reload the page.
|
||||
|
||||
Example:
|
||||
|
||||
@ -91,3 +94,7 @@ Example:
|
||||
console.log(JSON.stringify(result));
|
||||
});
|
||||
|
||||
You do however need to configure proper access rights for your ubus methods
|
||||
before you can call them. This is part of the access list (acl) configuration.
|
||||
|
||||
|
||||
|
@ -1,42 +1,42 @@
|
||||
# JUCI Ethernet Module
|
||||
JUCI Ethernet Subsystem
|
||||
=========
|
||||
|
||||
The ethernet module is responsible for managing ethernet devices (layer2) and
|
||||
providing a single point of entry for any ethernet related queries. It allows
|
||||
you to add plugins that also annotate existing ethernet devices and add other
|
||||
devices that belong to some specific subsystem such as adsl or wireless.
|
||||
Ethernet module gets it's information from "ip" command. After that it pipes
|
||||
the list of devices through all subsystems that it knows about. j Each
|
||||
subsystem can then either annotate existing devices - such as setting a proper
|
||||
device name based on wifi ssid or port configuration - or it can also add new
|
||||
devices to the list that may currently not be up (and thus not visible thorugh
|
||||
the ip command).
|
||||
This module is the core ethernet subsytem that ties together any other plugins that manage ethernet devices of some kind. It allows the user to have a standard interface for querying ethernet adapters. For example if you have a plugin for configuring vendor specific wireless settings then you would register that plugin as a subsystem of $ethernet and you will then be able to provide your vendor specific data as part of the list of adapters as it is returned by `getAdapters` method.
|
||||
|
||||
## Methods of $ethernet
|
||||
This plugin gets most of it's information from the ip(8) command and so it will always return a list of all adapters that the system knows about. However, things like adapter names and proper presentation of adapters is usually specific to the vendor. For example, you could have an ethernet port that is tied to an ethernet port with label LAN2 printed on the box. In this case this information will be probably provided by some board specific configuration file where you specifically assign interface names to the actual port numbers which are printed on the cover of the box. This is where subsystems come to resque because they allow you to implement your vendor speciffic package separately and then to annotate the existing list of adapters inside your callback which you register with the $ethernet subsystem.
|
||||
|
||||
addSubsystem(subsys) -> void
|
||||
METHODS
|
||||
=======
|
||||
|
||||
These are methods provided by the `$ethernet` factory when you add it to your parameter list to you page or widget controller.
|
||||
|
||||
`addSubsystem(subsys)` -> void
|
||||
|
||||
adds a new subsystem to list of subsystems. subsys can implement
|
||||
annotateAdapters(adapter:list) to modify the list of ethernet adapters
|
||||
before it will be returned to the user.
|
||||
adds a new subsystem to list of subsystems. subsys can implement
|
||||
annotateAdapters(adapter:list) to modify the list of ethernet adapters
|
||||
before it will be returned to the user.
|
||||
|
||||
getAdapters() -> promise
|
||||
`getAdapters()` -> promise
|
||||
|
||||
returns the list of ethernet adapters currently present on the system
|
||||
(both adapters that are actually present and the ones that are
|
||||
configured but may not yet be up).
|
||||
returns the list of ethernet adapters currently present on the system
|
||||
(both adapters that are actually present and the ones that are
|
||||
configured but may not yet be up).
|
||||
|
||||
## Methods of ethernet:subsystem
|
||||
EXPECTED SUBSYSTEM INTERFACE
|
||||
=======
|
||||
|
||||
annotateAdapters(adapter:list) -> promise
|
||||
These are methods that a subsystem would provide when it registers itself with the `$ethernet` subsystem.
|
||||
|
||||
This method is called by the ethernet subsystem to annotate the list of
|
||||
adapters before it is returned to the user. It takes the list of
|
||||
adapters to be annotated as parameter and returns a promise that should
|
||||
resolve once the operation has completed. The method should do what
|
||||
it's name suggests - it should annotate the list by either modifying
|
||||
it's existing properties in place or by adding new ones. This method
|
||||
returns a promise because it is common that such an operation will look
|
||||
inside other configuration files on the server before returning the
|
||||
modified list - all of which usually involves asynchronous operations.
|
||||
`annotateAdapters(adapter:list)` -> promise
|
||||
|
||||
This method is called by the ethernet subsystem to annotate the list of
|
||||
adapters before it is returned to the user. It takes the list of
|
||||
adapters to be annotated as parameter and returns a promise that should
|
||||
resolve once the operation has completed. The method should do what
|
||||
it's name suggests - it should annotate the list by either modifying
|
||||
it's existing properties in place or by adding new ones. This method
|
||||
returns a promise because it is common that such an operation will look
|
||||
inside other configuration files on the server before returning the
|
||||
modified list - all of which usually involves asynchronous operations.
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user