summaryrefslogtreecommitdiffhomepage
path: root/applications/luci-app-vpnbypass/htdocs/luci-static
diff options
context:
space:
mode:
authorStan Grishin <stangri@melmac.net>2021-03-10 04:32:00 +0000
committerStan Grishin <stangri@melmac.net>2021-03-14 02:34:01 +0000
commitd35cdc9dcc0e95e360a94a7b1c87df198768ac64 (patch)
treef34c44768bd89690bb81f3d9915a6b2d140c7638 /applications/luci-app-vpnbypass/htdocs/luci-static
parent2516852100eb6b115c0ad90883dfc5cfda16e076 (diff)
luci-app-vpnbypass: transition to client-side rendering
Signed-off-by: Stan Grishin <stangri@melmac.net>
Diffstat (limited to 'applications/luci-app-vpnbypass/htdocs/luci-static')
-rw-r--r--applications/luci-app-vpnbypass/htdocs/luci-static/resources/view/vpnbypass/overview.js62
-rw-r--r--applications/luci-app-vpnbypass/htdocs/luci-static/resources/vpnbypass/widgets.js192
2 files changed, 254 insertions, 0 deletions
diff --git a/applications/luci-app-vpnbypass/htdocs/luci-static/resources/view/vpnbypass/overview.js b/applications/luci-app-vpnbypass/htdocs/luci-static/resources/view/vpnbypass/overview.js
new file mode 100644
index 0000000000..b2d5d1f775
--- /dev/null
+++ b/applications/luci-app-vpnbypass/htdocs/luci-static/resources/view/vpnbypass/overview.js
@@ -0,0 +1,62 @@
+// Copyright 2021 Stan Grishin (stangri@melmac.net)
+// Many thanks to [@vsviridov](https://github.com/vsviridov) for help with transition to JS
+
+'use strict';
+'require form';
+'require uci';
+'require view';
+'require vpnbypass.widgets as widgets';
+
+var pkg = {
+ get Name() { return 'vpnbypass'; },
+ get URL() { return 'https://docs.openwrt.melmac.net/' + pkg.Name + '/'; }
+};
+
+return view.extend({
+ load: function () {
+ return Promise.all([
+ uci.load(pkg.Name),
+ uci.load('dhcp')
+ ]);
+ },
+
+ render: function (data) {
+
+ var m, d, s, o;
+
+ m = new form.Map(pkg.Name, _('VPN Bypass'));
+
+ s = m.section(form.NamedSection, 'config', pkg.Name);
+
+ o = s.option(widgets.Status, '', _('Service Status'));
+
+ o = s.option(widgets.Buttons, '', _('Service Control'));
+
+ o = s.option(form.DynamicList, 'localport', _('Local Ports to Bypass'), _('Local ports to trigger VPN Bypass.'));
+ o.datatype = 'portrange';
+ o.addremove = false;
+ o.optional = false;
+
+ o = s.option(form.DynamicList, 'remoteport', _('Remote Ports to Bypass'), _('Remote ports to trigger VPN Bypass.'));
+ o.datatype = 'portrange';
+ o.addremove = false;
+ o.optional = false;
+
+ o = s.option(form.DynamicList, 'localsubnet', _('Local IP Addresses to Bypass'), _('Local IP addresses or subnets with direct internet access.'));
+ o.datatype = 'ip4addr';
+ o.addremove = false;
+ o.optional = false;
+
+ o = s.option(form.DynamicList, 'remotesubnet', _('Remote IP Addresses to Bypass'), _('Remote IP addresses or subnets which will be accessed directly.'));
+ o.datatype = 'ip4addr';
+ o.addremove = false;
+ o.optional = false;
+
+ d = new form.Map('dhcp');
+ s = d.section(form.TypedSection, 'dnsmasq');
+ s.anonymous = true;
+ o = s.option(form.DynamicList, 'ipset', _('Domains to Bypass'), _('Domains to be accessed directly, see %sREADME%s for syntax.').format('<a href="' + pkg.URL + '#bypass-domains-formatsyntax" target="_blank" rel="noreferrer noopener">', '</a>'));
+
+ return Promise.all([m.render(), d.render()]);
+ }
+});
diff --git a/applications/luci-app-vpnbypass/htdocs/luci-static/resources/vpnbypass/widgets.js b/applications/luci-app-vpnbypass/htdocs/luci-static/resources/vpnbypass/widgets.js
new file mode 100644
index 0000000000..f14dd21d74
--- /dev/null
+++ b/applications/luci-app-vpnbypass/htdocs/luci-static/resources/vpnbypass/widgets.js
@@ -0,0 +1,192 @@
+// Thsis file wouldn't have been possible without help from [@vsviridov](https://github.com/vsviridov)
+
+'require ui';
+'require rpc';
+'require form';
+
+var pkg = {
+ get Name() { return 'vpnbypass'; }
+};
+
+var _getInitList = rpc.declare({
+ object: 'luci.' + pkg.Name,
+ method: 'getInitList',
+ params: ['name']
+});
+
+var _setInitAction = rpc.declare({
+ object: 'luci.' + pkg.Name,
+ method: 'setInitAction',
+ params: ['name', 'action'],
+ expect: { result: false }
+});
+
+var _getInitStatus = rpc.declare({
+ object: 'luci.' + pkg.Name,
+ method: 'getInitStatus',
+ params: ['name']
+});
+
+var RPC = {
+ listeners: [],
+ on: function on(event, callback) {
+ var pair = { event: event, callback: callback }
+ this.listeners.push(pair);
+ return function unsubscribe() {
+ this.listeners = this.listeners.filter(function (listener) {
+ return listener !== pair;
+ });
+ }.bind(this);
+ },
+ emit: function emit(event, data) {
+ this.listeners.forEach(function (listener) {
+ if (listener.event === event) {
+ listener.callback(data);
+ }
+ });
+ },
+ getInitList: function getInitList(name) {
+ _getInitList(name).then(function (result) {
+ this.emit('getInitList', result);
+ }.bind(this));
+
+ },
+ getInitStatus: function getInitStatus(name) {
+ _getInitStatus(name).then(function (result) {
+ this.emit('getInitStatus', result);
+ }.bind(this));
+ },
+ setInitAction: function setInitAction(name, action) {
+ _setInitAction(name, action).then(function (result) {
+ this.emit('setInitAction', result);
+ }.bind(this));
+ }
+}
+
+var statusCBI = form.DummyValue.extend({
+ renderWidget: function (section) {
+ var status = E('span', {}, _("Quering") + "...");
+ RPC.on('getInitStatus', function (reply) {
+ if (reply[pkg.Name].version) {
+ if (reply[pkg.Name].running) {
+ status.innerText = _("Running (version: %s)").format(reply[pkg.Name].version);
+ }
+ else {
+ if (reply[pkg.Name].enabled) {
+ status.innerText = _("Stopped (version: %s)").format(reply[pkg.Name].version);
+ }
+ else {
+ status.innerText = _("Stopped (Disabled)");
+ }
+ }
+ }
+ else {
+ status.innerText = _("Not installed or not found")
+ }
+ });
+ return E('div', {}, [status]);
+ }
+});
+
+var buttonsCBI = form.DummyValue.extend({
+ renderWidget: function (section) {
+
+ var btn_gap = E('span', {}, '&nbsp;&nbsp;');
+ var btn_gap_long = E('span', {}, '&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;');
+
+ var btn_start = E('button', {
+ 'class': 'btn cbi-button cbi-button-apply',
+ disabled: true,
+ click: function (ev) {
+ ui.showModal(null, [
+ E('p', { 'class': 'spinning' }, _('Starting %s service').format(pkg.Name))
+ ]);
+ return RPC.setInitAction(pkg.Name, 'start');
+ }
+ }, _('Start'));
+
+ var btn_action = E('button', {
+ 'class': 'btn cbi-button cbi-button-apply',
+ disabled: true,
+ click: function (ev) {
+ ui.showModal(null, [
+ E('p', { 'class': 'spinning' }, _('Restarting %s service').format(pkg.Name))
+ ]);
+ return RPC.setInitAction(pkg.Name, 'restart');
+ }
+ }, _('Restart'));
+
+ var btn_stop = E('button', {
+ 'class': 'btn cbi-button cbi-button-reset',
+ disabled: true,
+ click: function (ev) {
+ ui.showModal(null, [
+ E('p', { 'class': 'spinning' }, _('Stopping %s service').format(pkg.Name))
+ ]);
+ return RPC.setInitAction(pkg.Name, 'stop');
+ }
+ }, _('Stop'));
+
+ var btn_enable = E('button', {
+ 'class': 'btn cbi-button cbi-button-apply',
+ disabled: true,
+ click: function (ev) {
+ ui.showModal(null, [
+ E('p', { 'class': 'spinning' }, _('Enabling %s service').format(pkg.Name))
+ ]);
+ return RPC.setInitAction(pkg.Name, 'enable');
+ }
+ }, _('Enable'));
+
+ var btn_disable = E('button', {
+ 'class': 'btn cbi-button cbi-button-reset',
+ disabled: true,
+ click: function (ev) {
+ ui.showModal(null, [
+ E('p', { 'class': 'spinning' }, _('Disabling %s service').format(pkg.Name))
+ ]);
+ return RPC.setInitAction(pkg.Name, 'disable');
+ }
+ }, _('Disable'));
+
+ RPC.on('getInitStatus', function (reply) {
+ if (reply[pkg.Name].version) {
+ if (reply[pkg.Name].enabled) {
+ btn_enable.disabled = true;
+ btn_disable.disabled = false;
+ if (reply[pkg.Name].running) {
+ btn_start.disabled = true;
+ btn_action.disabled = false;
+ btn_stop.disabled = false;
+ }
+ else {
+ btn_start.disabled = false;
+ btn_action.disabled = true;
+ btn_stop.disabled = true;
+ }
+ }
+ else {
+ btn_start.disabled = true;
+ btn_action.disabled = true;
+ btn_stop.disabled = true;
+ btn_enable.disabled = false;
+ btn_disable.disabled = true;
+ }
+ }
+ });
+
+ RPC.getInitStatus(pkg.Name);
+
+ return E('div', {}, [btn_start, btn_gap, btn_action, btn_gap, btn_stop, btn_gap_long, btn_enable, btn_gap, btn_disable]);
+ }
+});
+
+RPC.on('setInitAction', function (reply) {
+ ui.hideModal();
+ RPC.getInitStatus(pkg.Name);
+});
+
+return L.Class.extend({
+ Status: statusCBI,
+ Buttons: buttonsCBI
+});