0
0
mirror of https://github.com/openwrt/luci.git synced 2025-02-07 02:19:53 +00:00
George Sapkin f32d9204a7 luci-app-example: rewrite RPC side using ucode
Signed-off-by: George Sapkin <george@sapk.in>
2025-02-03 15:07:18 +01:00

147 lines
4.2 KiB
JavaScript

'use strict';
'require form';
'require rpc';
'require view';
/*
Declare the RPC calls that are needed. The object value maps to the name
listed by the shell command
$ ubus list
Custom ucode scripts can be placed in /usr/share/rpcd/ucode, and must emit JSON.
Permissions to make these calls must be granted in /usr/share/rpcd/acl.d
via a file named the same as the application package name (luci-app-example)
*/
const load_sample1 = rpc.declare({
object: 'luci.example',
method: 'get_sample1'
});
// Out of the box, this one will be blocked by the framework because there is
// no ACL granting permission.
const load_sample3 = rpc.declare({
object: 'luci.example',
method: 'get_sample3'
});
return view.extend({
generic_failure: function (message) {
// Map an error message into a div for rendering
return E('div', {
'class': 'error'
}, [_('RPC call failure: '), message])
},
render_sample1_using_array: function (sample) {
console.log('render_sample1_using_array()');
console.log(sample);
/*
Some simple error handling. If the RPC APIs return a JSON structure of the
form {"error": "Some error message"} when there's a failure, then the UI
can check for the presence of the error attribute, and render a failure
widget instead of breaking completely.
*/
if (sample.error) {
return this.generic_failure(sample.error)
}
/*
Approach 1 for mapping JSON data to a simple table for display. The listing looks
a bit like key/value pairs, but is actually just an array. The loop logic later
on must iterate by 2 to get the labels.
*/
const fields = [
_('Cats'), sample.num_cats,
_('Dogs'), sample.num_dogs,
_('Parakeets'), sample.num_parakeets,
_('Should be "Not found"'), sample.not_found,
_('Is this real?'), sample.is_this_real ? _('Yes') : _('No'),
];
/*
Declare a table element using an automatically available function - E(). E()
produces a DOM node, where the first argument is the type of node to produce,
the second argument is an object of attributes for that node, and the third
argument is an array of child nodes (which can also be E() calls).
*/
var table = E('table', {
'class': 'table',
'id': 'approach-1'
});
// Loop over the array, starting from index 0. Every even-indexed second element is
// the label (left column) and the odd-indexed elements are the value (right column)
for (var i = 0; i < fields.length; i += 2) {
table.appendChild(
E('tr', {
'class': 'tr'
}, [
E('td', {
'class': 'td left',
'width': '33%'
}, [fields[i]]),
E('td', {
'class': 'td left'
}, [(fields[i + 1] != null) ? fields[i + 1] : _('Not found')])
]));
}
return table;
},
/*
load() is called on first page load, and the results of each promise are
placed in an array in the call order. This array is passed to the render()
function as the first argument.
*/
load: function () {
return Promise.all([
load_sample1()
]);
},
// render() is called by the LuCI framework to do any data manipulation, and the
// return is used to modify the DOM that the browser shows.
render: function (data) {
// data[0] will be the result from load_sample1
const sample1 = data[0] || {};
// Render the tables as individual sections.
return E('div', {}, [
E('div', {
'class': 'cbi-section warning'
}, _('See browser console for raw data')),
E('div', {
'class': 'cbi-map',
'id': 'map'
}, [
E('div', {
'class': 'cbi-section',
'id': 'cbi-sample-js'
}, [
E('div', {
'class': 'left'
}, [
// _() notation on strings is used for translation detection
E('h3', _('Sample JS via RPC')),
E('div', {}), _(
"JSON converted to table via array building and loop"
),
this.render_sample1_using_array(sample1)
]),
]),
]),
]);
},
/*
Since this is a view-only screen, the handlers are disabled
Normally, when using something like Map or JSONMap, you would
not null out these handlers, so that the form can be saved/applied.
With a RPC data source, you would need to define custom handlers
that verify the changes, and make RPC calls to a backend that can
process the request.
*/
handleSave: null,
handleSaveApply: null,
handleReset: null
})