Skip to content
Snippets Groups Projects
Unverified Commit 31d3f08f authored by Matthias Schiffer's avatar Matthias Schiffer
Browse files

treewide: convert all LuCI-based packages to gluon-web

parent e4b74be5
No related branches found
No related tags found
No related merge requests found
Showing
with 220 additions and 227 deletions
......@@ -99,7 +99,7 @@ config: FORCE
&& scripts/target_config.sh generic \
&& GLUON_SITEDIR='$(GLUON_SITEDIR)' scripts/target_config.sh '$(GLUON_TARGET)' \
$(foreach pkg,$(GLUON_PACKAGES_YES),&& echo 'CONFIG_PACKAGE_$(pkg)=y') \
$(foreach lang,$(GLUON_LANGS),&& echo 'CONFIG_LUCI_LANG_$(lang)=y') \
$(foreach lang,$(GLUON_LANGS),&& echo 'CONFIG_GLUON_WEB_LANG_$(lang)=y') \
&& echo 'CONFIG_GLUON_RELEASE="$(GLUON_RELEASE)"' \
&& echo 'CONFIG_GLUON_SITEDIR="$(GLUON_SITEDIR)"' \
&& echo 'CONFIG_GLUON_BRANCH="$(GLUON_BRANCH)"' \
......
Config Mode
===========
As of 2014.4 `gluon-config-mode` consists of several modules.
The `Config Mode` consists of several modules that provide a range of different
condiguration options:
gluon-config-mode-core
This modules provides the core functionality for the config mode.
......@@ -22,20 +23,13 @@ gluon-config-mode-geo-location
gluon-config-mode-contact-info
Adds a field where the user can provide contact information.
In order to get a config mode close to the one found in 2014.3.x you may add
these modules to your `site.mk`:
gluon-config-mode-hostname,
gluon-config-mode-autoupdater,
gluon-config-mode-mesh-vpn,
gluon-config-mode-geo-location,
gluon-config-mode-contact-info
Writing Config Mode Modules
Writing Config Mode modules
~~~~~~~~~~~~~~~~~~~~~~~~~~~
Config mode modules are located at `/lib/gluon/config-mode/wizard` and
`/lib/gluon/config-mode/reboot`. Modules are named like `0000-name.lua` and
are executed in lexical order. If you take the standard set of modules, the
Config mode modules are located at ``/lib/gluon/config-mode/wizard`` and
``/lib/gluon/config-mode/reboot``. Modules are named like ``0000-name.lua`` and
are executed in lexical order. In the standard package set, the
order is, for wizard modules:
- 0050-autoupdater-info
......@@ -44,49 +38,45 @@ order is, for wizard modules:
- 0400-geo-location
- 0500-contact-info
While for reboot modules it is:
The reboot module order is:
- 0100-mesh-vpn
- 0900-msg-reboot
All modules are run in the gluon-web model context and have access to the same
variables as "full" gluon-web modules.
Wizards
-------
Wizard modules return a UCI section. A simple module capable of changing the
hostname might look like this::
Wizard modules must return a function that is provided with the wizard form and an
UCI cursor. The function can create configuration sections in the form:
local cbi = require "luci.cbi"
local uci = luci.model.uci.cursor()
.. code-block:: lua
local M = {}
function M.section(form)
local s = form:section(cbi.SimpleSection, nil, nil)
local o = s:option(cbi.Value, "_hostname", "Hostname")
o.value = uci:get_first("system", "system", "hostname")
o.rmempty = false
return function(form, uci)
local s = form:section(Section)
local o = s:option(Value, "hostname", "Hostname")
o.default = uci:get_first("system", "system", "hostname")
o.datatype = "hostname"
end
function M.handle(data)
uci:set("system", uci:get_first("system", "system"), "hostname", data._hostname)
uci:save("system")
uci:commit("system")
function o:write(data)
uci:set("system", uci:get_first("system", "system"), "hostname", data)
end
return {'system'}
end
return M
The function may return a table of UCI packages to commit after the individual
fields' `write` methods have been executed. This is done to avoid committing the
packages repeatedly when multiple wizard modules modify the same package.
Reboot page
-----------
Reboot modules return a function that will be called when the page is to be
rendered or nil (i.e. the module is skipped)::
Reboot modules are simply executed when the reboot page is
rendered:
if no_hello_world_today then
return nil
else
return function ()
luci.template.render_string("Hello World!")
end
end
.. code-block:: lua
renderer.render_string("Hello World!")
......@@ -10,53 +10,56 @@ General guidelines
nice-to-have, but not required. If you don't know a language well, rather leave the translation
blank, so it is obvious that there is no proper translation yet.
* Existing expert mode packages should be made translatable as soon as possible.
* The "message IDs" (which are the arguments to the ``translate`` function) should be the
* The "message IDs" (which are the arguments to the *translate* function) should be the
English texts.
i18n support in LuCI
--------------------
i18n support in Gluon
---------------------
Internationalization support can be found in the ``luci.i18n`` package.
Strings are translated using the ``i18n.translate`` and ``i18n.translatef`` functions
(``translate`` for static strings, ``translatef`` for printf-like formatted string).
Internationalization support is available in all components (models, view and
contrllers) of *gluon-web*-based packages. Strings are translated using the *translate*
and *translatef* functions (*translate* for static strings, *translatef*
for printf-like formatted string); in views, the special tags ``<%:...%>`` can
be used to translate the contained string.
Example from the ``gluon-config-mode-geo-location`` package::
Example from the *gluon-config-mode-geo-location* package:
local i18n = require "luci.i18n"
o = s:option(cbi.Flag, "_location", i18n.translate("Show node on the map"))
.. code-block:: lua
local share_location = s:option(Flag, "location", translate("Show node on the map"))
Adding translation templates to Gluon packages
----------------------------------------------
The i18n support is based on the standard gettext system. For each translatable package,
a translation template with extension ``.pot`` can be created using the ``i18n-scan.pl``
script from the LuCI repository::
a translation template with extension ``.pot`` can be created using the *i18n-scan.pl*
script in the ``contrib`` directory:
.. code-block:: sh
cd package/gluon-config-mode-geo-location
cd package/gluon-web-mesh-vpn-fastd
mkdir i18n
cd i18n
../../../packages/luci/build/i18n-scan.pl ../files > gluon-config-mode-geo-location.pot
../../../contrib/i18n-scan.pl ../files ../luasrc > gluon-web-mesh-vpn-fastd.pot
The entries in the template can be reordered after the generation if desirable. Lots of standard
translations like "Cancel" are already available in the LuCI base translation file (see
``packages/luci/po/templates/base.pot``) and can be removed from the template.
The same command can be run again to update the template.
In addition, some additions to the Makefile must be made. Instead of OpenWrt's default ``package.mk``,
the Gluon version ``$(GLUONDIR)/include/package.mk`` must be used. The i18n files must be installed
In addition, some additions to the Makefile must be made. Instead of LEDE's default *package.mk*,
the Gluon version (``../gluon.mk`` for core packages) must be used. The i18n files must be installed
and PKG_CONFIG_DEPENDS must be added::
...
include $(GLUONDIR)/include/package.mk
include ../gluon.mk
PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG)
...
define Build/Compile
$(call GluonBuildI18N,gluon-config-mode-geo-location,i18n)
$(call GluonBuildI18N,gluon-web-mesh-vpn-fastd,i18n)
endef
define Package/gluon-config-mode-geo-location/install
define Package/gluon-web-mesh-vpn-fastd/install
...
$(call GluonInstallI18N,gluon-config-mode-geo-location,$(1))
$(call GluonInstallI18N,gluon-web-mesh-vpn-fastd,$(1))
endef
...
......@@ -64,29 +67,29 @@ and PKG_CONFIG_DEPENDS must be added::
Adding translations
-------------------
A new translation file for a template can be added using the ``msginit`` command::
A new translation file for a template can be added using the *msginit* command:
.. code-block:: sh
cd package/gluon-config-mode-geo-location/i18n
cd package/gluon-web-mesh-vpn-fastd/i18n
msginit -l de
This will create the file ``de.po`` in which the translations can be added.
This will create the file *de.po* in which the translations can be added.
The translation file can be updated to a new template version using the ``msgmerge`` command::
The translation file can be updated to a new template version using the *msgmerge* command:
msgmerge -U de.po gluon-config-mode-geo-location.pot
.. code-block:: sh
msgmerge -U de.po gluon-web-mesh-vpn-fastd.pot
After the merge, the translation file should be checked for "fuzzy matched" entries where
the original English texts have changed. All entries from the translation file should be
translated in the ``.po`` file (or removed from it, so the original English texts are displayed
translated in the *.po* file (or removed from it, so the original English texts are displayed
instead).
Adding support for new languages
--------------------------------
A list of all languages supported by LuCI can be found in the ``packages/luci/luci.mk`` file after
Gluon's dependencies have been downloaded using ``make update``. Adding translations for these
languages is straightforward using the ``msginit`` command.
For other languages, support must be added to LuCI first, which constitutes completely translating
the ``base.pot``. Please contact the upstream LuCI maintainers at https://github.com/openwrt/luci/
if you'd like to do this.
A list of all languages supported by *gluon-web* can be found in ``package/gluon.mk``.
New languages just need to be added to *GLUON_SUPPORTED_LANGS*, after a human-readable
language name has been defined in the same file.
......@@ -16,7 +16,7 @@ Best practices
--------------
* Most upgrade scripts are written in Lua. This allows using lots of helper functions provided
by LuCi and Gluon, e.g. to access the site configuration or edit UCI configuration files.
by Gluon, e.g. to access the site configuration or edit UCI configuration files.
* Whenever possible, scripts shouldn't check if they are running for the first time, but just edit configuration
files to achive a valid configuration (without overwriting configuration changes made by the user where desirable).
......
......@@ -4,7 +4,7 @@ Private WLAN
It is possible to set up a private WLAN that bridges the WAN port and is seperated from the mesh network.
Please note that you should not enable ``mesh_on_wan`` simultaneously.
The private WLAN can be enabled through the config mode if the package ``gluon-luci-private-wifi`` is installed.
The private WLAN can be enabled through the config mode if the package ``gluon-web-private-wifi`` is installed.
You may also enable a private WLAN using the command line::
uci set wireless.wan_radio0=wifi-iface
......
......@@ -18,13 +18,13 @@ For this the section ``roles`` in ``site.conf`` is needed::
},
},
The strings to display in the LuCI interface are configured per language in the
The strings to display in the web interface are configured per language in the
``i18n/en.po``, ``i18n/de.po``, etc. files of the site repository using message IDs like
``gluon-luci-node-role:role:node`` and ``gluon-luci-node-role:role:backbone``.
``gluon-web-node-role:role:node`` and ``gluon-web-node-role:role:backbone``.
The value of ``default`` is the role every node will initially own. This value should be part of ``list`` as well.
If you want node owners to change the defined roles via config-mode you can add the package
``gluon-luci-node-role`` to your ``site.mk``.
``gluon-web-node-role`` to your ``site.mk``.
The role is saved in ``gluon-node-info.system.role``. To change the role using command line do::
......
......@@ -19,7 +19,7 @@ Configuration
~~~~~~~~~~~~~
Both Mesh-on-WAN and Mesh-on-LAN can be configured on the "Network" page
of the *Advanced settings* (if the package ``gluon-luci-portconfig`` is installed).
of the *Advanced settings* (if the package ``gluon-web-network`` is installed).
It is also possible to enable Mesh-on-WAN and Mesh-on-LAN by default by
adding ``mesh_on_wan = true`` and ``mesh_on_lan = true`` to ``site.conf``.
......
......@@ -15,10 +15,10 @@ GLUON_SITE_PACKAGES := \
gluon-config-mode-mesh-vpn \
gluon-ebtables-filter-multicast \
gluon-ebtables-filter-ra-dhcp \
gluon-luci-admin \
gluon-luci-autoupdater \
gluon-luci-portconfig \
gluon-luci-wifi-config \
gluon-web-admin \
gluon-web-autoupdater \
gluon-web-network \
gluon-web-wifi-config \
gluon-mesh-batman-adv-15 \
gluon-mesh-vpn-fastd \
gluon-radvd \
......
......@@ -182,7 +182,7 @@ fastd_mesh_vpn
with the list from the site configuration. Setting `configurable` to `true` will allow the user to
add the method ``null`` to the beginning of the method list or remove ``null`` from it,
and make this change survive updates. Setting `configurable` is necessary for the
package `gluon-luci-mesh-vpn-fastd`, which adds a UI for this configuration.
package `gluon-web-mesh-vpn-fastd`, which adds a UI for this configuration.
In any case, the ``null`` method should always be the first method in the list
if it is supported at all. You should only set `configurable` to `true` if the
......@@ -288,11 +288,11 @@ roles \: optional
the community which roles to define. See the section below as an example.
``default`` takes the default role which is set initially. This value should be
part of ``list``. If you want node owners to change the role via config mode add
the package ``gluon-luci-node-role`` to ``site.mk``.
the package ``gluon-web-node-role`` to ``site.mk``.
The strings to display in the LuCI interface are configured per language in the
The strings to display in the web interface are configured per language in the
``i18n/en.po``, ``i18n/de.po``, etc. files of the site repository using message IDs like
``gluon-luci-node-role:role:node`` and ``gluon-luci-node-role:role:backbone``.
``gluon-web-node-role:role:node`` and ``gluon-web-node-role:role:backbone``.
::
roles = {
......
......@@ -13,14 +13,10 @@ PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG)
define Package/gluon-config-mode-autoupdater
SECTION:=gluon
CATEGORY:=Gluon
TITLE:=Let the user know whether the autoupdater is enabled or not.
TITLE:=Config Mode: Let the user know whether the autoupdater is enabled or not
DEPENDS:=gluon-config-mode-core-virtual +gluon-autoupdater
endef
define Package/gluon-config-mode-autoupdater/description
Luci based config mode
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
endef
......
local cbi = require "luci.cbi"
local i18n = require "luci.i18n"
local uci = require("simple-uci").cursor()
local M = {}
function M.section(form)
local enabled = uci:get_bool("autoupdater", "settings", "enabled")
if enabled then
local s = form:section(cbi.SimpleSection, nil,
i18n.translate('This node will automatically update its firmware when a new version is available.'))
end
return function(form, uci)
if uci:get_bool("autoupdater", "settings", "enabled") then
local s = form:section(
Section, nil,
translate('This node will automatically update its firmware when a new version is available.')
)
end
end
function M.handle(data)
return
end
return M
local cbi = require "luci.cbi"
local i18n = require "luci.i18n"
local uci = require("simple-uci").cursor()
local site = require 'gluon.site_config'
return function(form, uci)
local site = require 'gluon.site_config'
local M = {}
local owner = uci:get_first("gluon-node-info", "owner")
function M.section(form)
local s = form:section(cbi.SimpleSection, nil, i18n.translate(
'Please provide your contact information here to '
.. 'allow others to contact you. Note that '
.. 'this information will be visible <em>publicly</em> '
.. 'on the internet together with your node\'s coordinates.'
)
)
local s = form:section(Section, nil, translate(
'Please provide your contact information here to '
.. 'allow others to contact you. Note that '
.. 'this information will be visible <em>publicly</em> '
.. 'on the internet together with your node\'s coordinates.'
))
local o = s:option(cbi.Value, "_contact", i18n.translate("Contact info"))
o.default = uci:get_first("gluon-node-info", "owner", "contact", "")
o.rmempty = not ((site.config_mode or {}).owner or {}).obligatory
o.datatype = "string"
o.description = i18n.translate("e.g. E-mail or phone number")
o.maxlen = 140
end
local o = s:option(Value, "contact", translate("Contact info"), translate("e.g. E-mail or phone number"))
o.default = uci:get("gluon-node-info", owner, "contact")
o.optional = not ((site.config_mode or {}).owner or {}).obligatory
-- without a minimal length, an empty string will be accepted even with "optional = false"
o.datatype = "minlength(1)"
function o:write(data)
if data then
uci:set("gluon-node-info", owner, "contact", data)
else
uci:delete("gluon-node-info", owner, "contact")
end
end
function M.handle(data)
if data._contact ~= nil then
uci:set("gluon-node-info", uci:get_first("gluon-node-info", "owner"), "contact", data._contact)
else
uci:delete("gluon-node-info", uci:get_first("gluon-node-info", "owner"), "contact")
end
uci:save("gluon-node-info")
uci:commit("gluon-node-info")
return {'gluon-node-info'}
end
return M
......@@ -16,8 +16,8 @@ PKG_CONFIG_DEPENDS += $(GLUON_I18N_CONFIG)
define Package/gluon-config-mode-core
SECTION:=gluon
CATEGORY:=Gluon
TITLE:=Luci based config mode for user friendly setup of new mesh nodes
DEPENDS:=gluon-setup-mode-virtual +gluon-luci-theme +gluon-lock-password +pretty-hostname $(GLUON_I18N_PACKAGES)
TITLE:=Configuration wizard for user friendly setup of new mesh nodes
DEPENDS:=gluon-setup-mode-virtual +gluon-web-theme +gluon-lock-password +pretty-hostname
PROVIDES:=gluon-config-mode-core-virtual
endef
......
<h2><%:Your node's setup is now complete.%></h2>
<%
local fs = require "nixio.fs"
local util = require "nixio.util"
local parts_dir = "/lib/gluon/config-mode/reboot/"
local files = util.consume(fs.dir(parts_dir) or function() end)
table.sort(files)
local parts = {}
for _, entry in ipairs(files) do
if entry:sub(1, 1) ~= '.' then
local p = assert(loadfile(parts_dir .. entry))
setfenv(p, getfenv())
table.insert(parts, p)
end
end
for _, p in ipairs(parts) do
p()
end
%>
<%-
local sysconfig = require 'gluon.sysconfig'
-%>
<p>
<%=
renderer.render_string(translate('gluon-config-mode:welcome'), {
hostname = hostname,
sysconfig = sysconfig,
})
%>
</p>
<%-
local gluon_luci = require 'gluon.luci'
local sysconfig = require 'gluon.sysconfig'
local i18n = require 'luci.i18n'
local template = require 'luci.template'
-%>
<h2><%:Welcome!%></h2>
<p>
<%= template.render_string(i18n.translate('gluon-config-mode:welcome'), {
hostname = hostname,
sysconfig = sysconfig,
escape = gluon_luci.escape,
urlescape = gluon_luci.urlescape,
}) %>
</p>
<% if not self.embedded then %>
<form method="post" enctype="multipart/form-data" action="<%=REQUEST_URI%>">
<div>
<script type="text/javascript" src="<%=resource%>/cbi.js"></script>
<input type="hidden" name="token" value="<%=token%>" />
<input type="hidden" name="cbi.submit" value="1" />
</div>
<% end %>
<div class="cbi-map" id="cbi-<%=self.config%>">
<% if self.title and #self.title > 0 then %><h2><a id="content" name="content"><%=self.title%></a></h2><% end %>
<% if self.description and #self.description > 0 then %><div class="cbi-map-descr"><%=self.description%></div><% end %>
<% self:render_children() %>
<br />
</div>
<%- if self.message then %>
<div><%=self.message%></div>
<%- end %>
<%- if self.errmessage then %>
<div class="error"><%=self.errmessage%></div>
<%- end %>
<% if not self.embedded then %>
<div class="cbi-page-actions">
<%-
if type(self.hidden) == "table" then
for k, v in pairs(self.hidden) do
-%>
<input type="hidden" id="<%=k%>" name="<%=k%>" value="<%=pcdata(v)%>" />
<%-
end
end
%>
<input class="cbi-button cbi-button-save" type="submit" value="<%:Save & restart%>" />
<script type="text/javascript">cbi_d_update();</script>
</div>
</form>
<% end %>
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<%=luci.i18n.context.lang%>" lang="<%=luci.i18n.context.lang%>">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title><%=escape(hostname)%> is rebooting</title>
<link rel="stylesheet" type="text/css" media="screen" href="<%=media%>/cascade.css" />
</head>
<body>
<div id="maincontainer">
<div id="maincontent">
<h2><%:Your node's setup is now complete.%></h2>
<% for k, v in ipairs(parts) do v() end %>
</div>
</div>
</body>
</html>
local i18n = require 'luci.i18n'
local site = require 'gluon.site_config'
local gluon_luci = require 'gluon.luci'
local sysconfig = require 'gluon.sysconfig'
local pretty_hostname = require 'pretty_hostname'
......@@ -9,15 +7,11 @@ local uci = require("simple-uci").cursor()
local hostname = pretty_hostname.get(uci)
local contact = uci:get_first('gluon-node-info', 'owner', 'contact')
local msg = i18n.translate('gluon-config-mode:reboot')
local msg = translate('gluon-config-mode:reboot')
return function ()
luci.template.render_string(msg, {
hostname = hostname,
site = site,
sysconfig = sysconfig,
contact = contact,
escape = gluon_luci.escape,
urlescape = gluon_luci.urlescape,
})
end
renderer.render_string(msg, {
hostname = hostname,
site = site,
sysconfig = sysconfig,
contact = contact,
})
entry({}, alias("wizard"))
entry({"wizard"}, model("gluon-config-mode/wizard"), _("Wizard"), 5)
local disp = require 'gluon.web.dispatcher'
local fs = require "nixio.fs"
local util = require "gluon.web.util"
local nixio_util = require "nixio.util"
local uci = require("simple-uci").cursor()
local wizard_dir = "/lib/gluon/config-mode/wizard/"
local files = nixio_util.consume(fs.dir(wizard_dir) or function() end)
table.sort(files)
local wizard = {}
for _, entry in ipairs(files) do
if entry:sub(1, 1) ~= '.' then
local f = assert(loadfile(wizard_dir .. entry))
setfenv(f, getfenv())
local w = f()
table.insert(wizard, w)
end
end
local f = Form(translate("Welcome!"))
f.submit = translate('Save & restart')
f.reset = false
local s = f:section(Section)
s.template = "gluon/config-mode/welcome"
local commit = {'gluon-setup-mode'}
for _, w in ipairs(wizard) do
for _, c in ipairs(w(f, uci) or {}) do
if not util.contains(commit, c) then
table.insert(commit, c)
end
end
end
function f:write()
local nixio = require "nixio"
uci:set("gluon-setup-mode", uci:get_first("gluon-setup-mode", "setup_mode"), "configured", true)
for _, c in ipairs(commit) do
uci:commit(c)
end
f.template = "gluon/config-mode/reboot"
f.hidenav = true
if nixio.fork() == 0 then
-- Replace stdout with /dev/null
nixio.dup(nixio.open('/dev/null', 'w'), nixio.stdout)
-- Sleep a little so the browser can fetch everything required to
-- display the reboot page, then reboot the device.
nixio.nanosleep(1)
nixio.execp("reboot")
end
end
return f
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment