'use strict'; 'require form'; 'require rpc'; 'require ui'; 'require view'; var callInitAction = rpc.declare({ object: 'rc', method: 'init', params: ['name', 'action'], expect: { result: false } }); var callServiceList = rpc.declare({ object: 'service', method: 'list', params: ['name'], expect: { '': {} } }); return view.extend({ handleStart: function() { return callInitAction('copyparty', 'start').then(function() { return window.location.reload(); }); }, handleStop: function() { return callInitAction('copyparty', 'stop').then(function() { return window.location.reload(); }); }, render: function() { var self = this; return callServiceList('copyparty').then(function(res) { var instances = ((res.copyparty || {}).instances) || {}; var running = Object.keys(instances).some(function(k) { return instances[k].running; }); var m, s, o; m = new form.Map('copyparty', _('Copyparty'), _('Self-hosted file sharing server. Web UI at port 3923.').format(window.location.hostname)); /* ── Global settings ── */ s = m.section(form.NamedSection, 'config', 'copyparty', _('Settings')); s.addremove = false; o = s.option(form.Flag, 'enabled', _('Enable')); o.rmempty = false; o = s.option(form.Value, 'port', _('Port')); o.datatype = 'port'; o.default = '3923'; o.rmempty = false; o = s.option(form.Value, 'name', _('Server name')); o.default = 'OWRT-NAS'; o.rmempty = false; o = s.option(form.Value, 'script', _('Script path')); o.default = '/mnt/raid/copyparty-en.py'; o.rmempty = false; o = s.option(form.Flag, 'usernames', _('Require usernames'), _('If enabled, clients must supply a username in addition to password.')); o.rmempty = false; o = s.option(form.Value, 'tls_cert', _('TLS certificate'), _('Path to a PEM file containing the private key followed by the full certificate chain. Leave empty for HTTP.')); o.placeholder = '/etc/acme/owrt-nas.lan.1qaz.ca_ecc/copyparty.pem'; o.rmempty = true; /* ── Volumes ── */ s = m.section(form.GridSection, 'volume', _('Volumes'), _('Each volume maps a filesystem path to a URL path. Flags: r=read, w=write, m=move, d=delete, g=get.')); s.addremove = true; s.anonymous = true; s.addbtntitle = _('Add volume...'); o = s.option(form.Value, 'src', _('Source path')); o.rmempty = false; o.placeholder = '/mnt/raid/firstshare'; o = s.option(form.Value, 'dst', _('URL path')); o.rmempty = false; o.placeholder = '/files'; o = s.option(form.ListValue, 'flags', _('Access')); o.value('r', _('Read-only')); o.value('rw', _('Read/write')); o.value('rwmd', _('Read/write/move/delete')); o.default = 'r'; /* ── Accounts ── */ s = m.section(form.GridSection, 'account', _('Accounts'), _('Leave empty to allow anonymous access. Passwords are stored in plaintext in UCI.')); s.addremove = true; s.anonymous = true; s.addbtntitle = _('Add account...'); o = s.option(form.Value, 'user', _('Username')); o.rmempty = false; o = s.option(form.Value, 'pass', _('Password')); o.rmempty = false; o.password = true; return m.render().then(function(node) { var statusBadge = E('span', { style: 'font-weight:bold; color:' + (running ? '#2bab2b' : '#cc0000') }, running ? _('Running') : _('Stopped')); var btn = E('button', { class: 'cbi-button cbi-button-' + (running ? 'negative' : 'apply'), click: ui.createHandlerFn(self, running ? 'handleStop' : 'handleStart') }, running ? _('Stop') : _('Start')); var statusDiv = E('div', { class: 'cbi-section' }, [ E('h3', {}, _('Status')), E('div', { class: 'cbi-section-node' }, [ E('p', { style: 'margin:0' }, [ statusBadge, '  ', btn ]) ]) ]); node.insertBefore(statusDiv, node.querySelector('.cbi-section')); return node; }); }); } });