initial PoC for a Web interface

This commit is contained in:
Tobias Mueller 2023-10-16 11:53:08 +02:00
parent da1a2f071c
commit 61a7466117
5 changed files with 75 additions and 170 deletions

View File

@ -0,0 +1,3 @@
#!/bin/sh
echo Hello, World!

View File

@ -1,13 +1,13 @@
{ {
"admin/system/opkg2": { "admin/network/blue-merle": {
"title": "Software", "title": "Blue Merle",
"order": 30, "order": 30,
"action": { "action": {
"type": "view", "type": "view",
"path": "opkg2" "path": "opkg2"
}, },
"depends": { "depends": {
"acl": [ "luci-app-opkg2" ] "acl": [ "luci-app-blue-merle" ]
} }
} }
} }

View File

@ -0,0 +1,26 @@
{
"luci-app-blue-merle": {
"description": "Grant access to opkg management",
"read": {
"cgi-io": [ "exec" ],
"file": {
"/usr/libexec/blue-merle": [ "exec" ],
"/usr/libexec/blue-merle shred": [ "exec" ],
"/usr/libexec/blue-merle *": [ "exec" ],
"/etc/opkg.conf": [ "read" ],
"/etc/opkg/*.conf": [ "read" ]
},
"ubus": {
"luci": [ "getMountPoints" ]
}
},
"write": {
"file": {
"/usr/libexec/blue-merle": [ "exec" ],
"/usr/libexec/blue-merle shred": [ "exec" ],
"/usr/libexec/blue-merle *": [ "exec" ],
"/tmp/upload.ipk": [ "write" ]
}
}
}
}

View File

@ -1,29 +0,0 @@
{
"luci-app-opkg2": {
"description": "Grant access to opkg management",
"read": {
"cgi-io": [ "exec" ],
"file": {
"/usr/libexec/opkg-list installed": [ "exec" ],
"/usr/libexec/opkg-list available": [ "exec" ],
"/usr/libexec/opkg-call list-installed": [ "exec" ],
"/usr/libexec/opkg-call list-available": [ "exec" ],
"/etc/opkg.conf": [ "read" ],
"/etc/opkg/*.conf": [ "read" ]
},
"ubus": {
"luci": [ "getMountPoints" ]
}
},
"write": {
"file": {
"/usr/libexec/opkg-call install *": [ "exec" ],
"/usr/libexec/opkg-call remove *": [ "exec" ],
"/usr/libexec/opkg-call update *": [ "exec" ],
"/etc/opkg.conf": [ "write" ],
"/etc/opkg/*.conf": [ "write" ],
"/tmp/upload.ipk": [ "write" ]
}
}
}
}

View File

@ -199,140 +199,6 @@ function parseList(s, dest)
} }
} }
function display(pattern)
{
var src = packages[currentDisplayMode === 'updates' ? 'installed' : currentDisplayMode],
table = document.querySelector('#packages'),
pagers = document.querySelectorAll('.controls > .pager'),
i18n_filter = null;
currentDisplayRows.length = 0;
if (typeof(pattern) === 'string' && pattern.length > 0)
pattern = new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'), 'ig');
switch (document.querySelector('input[name="filter_i18n"]:checked').value) {
case 'all':
i18n_filter = /^luci-i18n-/;
break;
case 'lang':
i18n_filter = new RegExp('^luci-i18n-(base-.+|.+-(' + languages.join('|') + '))$');
break;
}
for (var name in src.pkgs) {
var pkg = src.pkgs[name],
desc = pkg.description || '',
altsize = null;
if (!pkg.size && packages.available.pkgs[name])
altsize = packages.available.pkgs[name].size;
if (!desc && packages.available.pkgs[name])
desc = packages.available.pkgs[name].description || '';
desc = desc.split(/\n/);
desc = desc[0].trim() + (desc.length > 1 ? '…' : '');
if ((pattern instanceof RegExp) &&
!name.match(pattern) && !desc.match(pattern))
continue;
if (name.indexOf('luci-i18n-') === 0 && (!(i18n_filter instanceof RegExp) || !name.match(i18n_filter)))
continue;
var btn, ver;
if (currentDisplayMode === 'updates') {
var avail = packages.available.pkgs[name],
inst = packages.installed.pkgs[name];
if (!inst || !inst.installed)
continue;
if (!avail || compareVersion(avail.version, pkg.version) <= 0)
continue;
ver = '%s » %s'.format(
truncateVersion(pkg.version || '-'),
truncateVersion(avail.version || '-'));
btn = E('div', {
'class': 'btn cbi-button-positive',
'data-package': name,
'click': handleInstall
}, _('Upgrade…'));
}
else if (currentDisplayMode === 'installed') {
if (!pkg.installed)
continue;
ver = truncateVersion(pkg.version || '-');
btn = E('div', {
'class': 'btn cbi-button-negative',
'data-package': name,
'click': handleRemove
}, _('Remove…'));
}
else {
var inst = packages.installed.pkgs[name];
ver = truncateVersion(pkg.version || '-');
if (!inst || !inst.installed)
btn = E('div', {
'class': 'btn cbi-button-action',
'data-package': name,
'click': handleInstall
}, _('Install…'));
else if (inst.installed && inst.version != pkg.version)
btn = E('div', {
'class': 'btn cbi-button-positive',
'data-package': name,
'click': handleInstall
}, _('Upgrade…'));
else
btn = E('div', {
'class': 'btn cbi-button-neutral',
'disabled': 'disabled'
}, _('Installed'));
}
name = '%h'.format(name);
desc = '%h'.format(desc || '-');
if (pattern) {
name = name.replace(pattern, '<ins>$&</ins>');
desc = desc.replace(pattern, '<ins>$&</ins>');
}
currentDisplayRows.push([
name,
ver,
pkg.size ? '%1024mB'.format(pkg.size)
: (altsize ? '~%1024mB'.format(altsize) : '-'),
desc,
btn
]);
}
currentDisplayRows.sort(function(a, b) {
if (a[0] < b[0])
return -1;
else if (a[0] > b[0])
return 1;
else
return 0;
});
for (var i = 0; i < pagers.length; i++) {
pagers[i].parentNode.style.display = '';
pagers[i].setAttribute('data-offset', 100);
}
handlePage({ target: pagers[0].querySelector('.prev') });
}
function handlePage(ev) function handlePage(ev)
{ {
@ -852,10 +718,49 @@ function handleConfig(ev)
{ {
var conf = {}; var conf = {};
ui.showModal(_('OPKG Configuration'), [ var cmd = "/usr/libexec/blue-merle";
E('p', { 'class': 'spinning' }, _('Loading configuration data…')) var dlg = ui.showModal(_('Executing blue merle'), [
E('p', { 'class': 'spinning' },
_('Waiting for the <em>%h</em> command to complete…').format(cmd))
]); ]);
var argv = []; //["shred"];
fs.exec_direct('/usr/libexec/blue-merle', argv, 'json').then(function(res) {
if (res.stdout)
dlg.appendChild(E('pre', [ res.stdout ]));
if (res.stderr) {
dlg.appendChild(E('h5', _('Errors')));
dlg.appendChild(E('pre', { 'class': 'errors' }, [ res.stderr ]));
}
if (res.code !== 0)
dlg.appendChild(E('p', _('The <em>opkg %h</em> command failed with code <code>%d</code>.').format(cmd, (res.code & 0xff) || -1)));
dlg.appendChild(E('div', { 'class': 'right' },
E('div', {
'class': 'btn',
'click': L.bind(function(res) {
if (ui.menu && ui.menu.flushCache)
ui.menu.flushCache();
ui.hideModal();
updateLists();
if (res.code !== 0)
rejectFn(new Error(res.stderr || 'opkg error %d'.format(res.code)));
else
resolveFn(res);
}, this, res)
}, _('Dismiss'))));
}).catch(function(err) {
ui.addNotification(null, E('p', _('Unable to execute <em>opkg %s</em> command: %s').format(cmd, err)));
ui.hideModal();
});
fs.list('/etc/opkg').then(function(partials) { fs.list('/etc/opkg').then(function(partials) {
var files = [ '/etc/opkg.conf' ]; var files = [ '/etc/opkg.conf' ];
@ -914,7 +819,7 @@ function handleConfig(ev)
}, _('Save')), }, _('Save')),
])); ]));
ui.showModal(_('OPKG Configuration'), body); //ui.showModal(_('OPKG Configuration'), body);
}); });
} }