[luci] Adding a page to luci
Andrew Peebles
peebles at cortina-systems.com
Wed Jan 9 03:34:53 CET 2013
On 01/08/2013 05:19 PM, Nguye^~n Ho^`ng Quân wrote:
> Hello,
>
> You can see my mod as a reference https://github.com/hongquan/KikiAuth
> I started from this doc:
> http://luci.subsignal.org/trac/wiki/Documentation/ModulesHowTo
> then http://luci.subsignal.org/trac/wiki/Documentation/CBI
> ...
>
> Hope you see it helpful.
>
> ***********************************************
> * Nguye^~n Ho^`ng Quân *
> * Y!M: ng_hquan_vn *
> * Identi.ca: hongquan *
> ***********************************************
>
>
> 2013/1/9 Frank Parker <mr.frank.parker at gmail.com
> <mailto:mr.frank.parker at gmail.com>>
>
> If someone here is willing to walk me through the steps required
> to customize my luci interface, I would be happy to document it.
> Seems useful since this is a common newbie question.
>
> My mod would be adding a single page with a single textbox that
> gets saved to /etc/config/myapp
>
> So for example, under System I would like to add a new tab called
> "MyApp" that displays a page with a single textbox. The value in
> the textbox gets saved to /etc/config/myapp. That's it.
>
> For bonus points, I also need a single button on the same page
> that will run a local script when clicked.
>
> On OpenWrt Backfire 10.03.1, I am hunting around in
> /usr/lib/lua/luci/* but not having much luck.
>
> Anyone?
>
> _______________________________________________
> luci mailing list
> luci at lists.subsignal.org <mailto:luci at lists.subsignal.org>
> https://lists.subsignal.org/mailman/listinfo/luci
>
>
>
>
> _______________________________________________
> luci mailing list
> luci at lists.subsignal.org
> https://lists.subsignal.org/mailman/listinfo/luci
I find that it easier, and more portable, to create a new package. The
instructions below do not include code/support for generating i18n
language files, but that can be wedged in.
First create a directory for the new package. Easiest is:
mkdir -p package/luci-app-myapp/files/controller
mkdir -p package/luci-app-myapp/files/model/cbi
mkdir -p package/luci-app-myapp/files/uci-defaults
This example will assume there is already a package called "myapp",
which installs its own /etc/init.d/myapp and /etc/config/myapp. That is
the typical break-out, so that myapp can be used in a system even
without a GUI. The package/luci-app-myapp/Makefile would look like:
include $(TOPDIR)/rules.mk
PKG_NAME:=luci-app-myapp
PKG_VERSION:=1
PKG_RELEASE:=1
include $(INCLUDE_DIR)/package.mk
define Package/luci-app-myapp
SECTION:=luci
CATEGORY:=LuCI
SUBMENU:=3. Applications
TITLE:=GUI for myapp package
PKGARCH:=all
DEPENDS:=+myapp
endef
define Build/Configure
endef
define Build/Compile
endef
define Package/luci-app-myapp/install
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/controller
$(INSTALL_DIR) $(1)/usr/lib/lua/luci/model/cbi
$(INSTALL_DIR) $(1)/etc/uci-defaults
$(CP) ./files/controller/myapp.lua \
$(1)/usr/lib/lua/luci/controller/
$(CP) ./files/model/cbi/myapp.lua \
$(1)/usr/lib/lua/luci/model/cbi/
$(CP) ./files/uci-defaults/luci-app-myapp \
$(1)/etc/uci-defaults/
endef
define Package/luci-app-myapp/postinst
#!/bin/sh
[ -n "$${IPKG_INSTROOT}" ] || {
if [ -f /etc/uci-defaults/luci-app-myapp ]; then
( . /etc/uci-defaults/luci-app-myapp ) && rm -f
/etc/uci-defaults/luci-app-myapp
fi
}
endef
$(eval $(call BuildPackage,luci-app-myapp))
Some interesting points above: DEPENDS makes sure that "mayapp" is
installed and selected for build when this package is selected. In the
install macro, the three pertinent files (the controller, the model and
the uci-defaults will get installed into the correct LuCI runtime
hierarchy. The postinst thing will run the luci-app-myapp script on the
target at installation time. That script should look like this:
#!/bin/sh
uci -q batch <<-EOF >/dev/null
delete ucitrack. at myapp[-1]
add ucitrack myapp
set ucitrack. at myapp[-1].init=myapp
commit ucitrack
EOF
rm -f /tmp/luci-indexcache
exit 0
This is the magic that ends up calling /etc/init.d/myapp when you click
on the Save&Apply button in LuCI.
Ok, so the controller (controller/myapp.lua) would look like this:
module("luci.controller.myapp", package.seeall)
function index()
-- dont show unless myapp package is installed
--
if not nixio.fs.access("/etc/config/myapp") then
return
end
local page
-- install this page into the hierarchy under admin -> services
page = entry({"admin", "services", "myapp"},
cbi("myapp"),
_("My Application"))
-- the i18n file's base name
page.i18n = "myapp"
page.dependent = true
end
And the model (model/cbi/myapp.lua) would look like:
-- "myapp" here refers to the name of the file in /etc/config
--
m = Map("myapp", translate("My Application"),
translate("Some optional additional text..."))
-- this refers to a section in the config file.
--
s = m:section( NamedSection, "configuration", "myapp",
translate("Settings"))
-- and then the options in that section
--
o = s:option( Value, "field", translate( "Field" ))
-- we're done!
--
return m
The way this model is written expects a /etc/config/myapp file that
looks like this:
config myapp configuration
option field 'some_initial_value'
At this point you should be able to "make menuconfig", select your new
package, and "make". I typed this entirely in my email client without
any actual verification, so there may be minor syntax errors, etc, and I
apologize for that in advance.
As for the bonus question about the button; as I know how to do things,
that is a fairly advanced topic. Its a little rough mixing cbi models
and gui stuff that is not part of the /etc/config file in question. cbi
models are fantastic if all you want to do is provide gui for config.
But, it is possible. It involves creating another option of type
DummyValue and creating a custom template for it. The template goes into
view/myapp/myview.htm. This template can paint any picture it wants.
You can place a button with an onclick javascript call or an href that
calls a function defined in the controller. You can even use ajax to
get json back from the call. I'll outline this from memory, so it might
also be a bit buggy, but maybe enough to set you down the right path:
In the controller, add a new entry that looks like this (in the index()
function):
entry({"admin", "services", "myapp", "func"},
call("action_func")).leaf = true
Now, in the same file, add a new function:
function action_func()
-- obtain any arguments passed (form entries or ajax data)
local field1 = luci.http.formvalue("field1")
-- do something, more interesting ...
-- then return json
luci.http.prepare_content("application/json")
luci.http.write_json({return_value = field1})
end
You can define as many of these entry points as you want. Now, in the
model file, add another option, something like this:
o = s:option(DummyValue, "_val", translate("Title"))
o.template = "myapp/myview.htm" -- is the html making up the gui
I *think* this is all you need. You then need to create the template
(and fix your Makefile to install it in the proper place). It might look
like:
<button onclick="doit();">My Button</button>
<script>
function doit() {
$.ajax({
url: '<%=luci.dispatcher.build_url("admin", "services", "myapp",
"func")%>',
data: {field1: 'it works!'},
dataType: 'json',
success: function(json) {
alert( json.return_value);
},
error: function(e, m) {
alert("Crap, spoke too soon: " + m);
}
});
}
</script>
Of course, that assumes you have jQuery installed and available (which
you can do here in this template). Or you can use the xhr.js that is
already available in LuCI themes. But you get the idea, I hope.
That has some chance of working. If its horribly broken and you can't
untangle it, lemme know and I'll actually try it and debug it for you.
a
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.subsignal.org/pipermail/luci/attachments/20130108/a7d65140/attachment-0001.html>
More information about the luci
mailing list