summaryrefslogtreecommitdiffhomepage
path: root/applications/luci-app-pbr/htdocs/luci-static/resources
diff options
context:
space:
mode:
Diffstat (limited to 'applications/luci-app-pbr/htdocs/luci-static/resources')
-rw-r--r--applications/luci-app-pbr/htdocs/luci-static/resources/pbr/status.js556
-rw-r--r--applications/luci-app-pbr/htdocs/luci-static/resources/view/pbr/overview.js650
-rw-r--r--applications/luci-app-pbr/htdocs/luci-static/resources/view/status/include/72_pbr.js88
3 files changed, 848 insertions, 446 deletions
diff --git a/applications/luci-app-pbr/htdocs/luci-static/resources/pbr/status.js b/applications/luci-app-pbr/htdocs/luci-static/resources/pbr/status.js
index 24f624c945..99a6e73844 100644
--- a/applications/luci-app-pbr/htdocs/luci-static/resources/pbr/status.js
+++ b/applications/luci-app-pbr/htdocs/luci-static/resources/pbr/status.js
@@ -3,7 +3,6 @@
"require ui";
"require rpc";
-"require uci";
"require form";
"require baseclass";
@@ -55,8 +54,8 @@ var _setInitAction = rpc.declare({
var RPC = {
listeners: [],
- on: function on(event, callback) {
- var pair = { event: event, callback: callback }
+ on: function (event, callback) {
+ var pair = { event: event, callback: callback };
this.listeners.push(pair);
return function unsubscribe() {
this.listeners = this.listeners.filter(function (listener) {
@@ -64,65 +63,77 @@ var RPC = {
});
}.bind(this);
},
- emit: function emit(event, data) {
+ emit: function (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));
+ getInitList: function (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));
+ getInitStatus: function (name) {
+ getInitStatus(name).then(
+ function (result) {
+ this.emit("getInitStatus", result);
+ }.bind(this)
+ );
},
- getGateways: function getGateways(name) {
- getGateways(name).then(function (result) {
- this.emit('getGateways', result);
- }.bind(this));
+ getGateways: function (name) {
+ getGateways(name).then(
+ function (result) {
+ this.emit("getGateways", result);
+ }.bind(this)
+ );
},
- getPlatformSupport: function getPlatformSupport(name) {
- getPlatformSupport(name).then(function (result) {
- this.emit('getPlatformSupport', result);
- }.bind(this));
+ getPlatformSupport: function (name) {
+ getPlatformSupport(name).then(
+ function (result) {
+ this.emit("getPlatformSupport", result);
+ }.bind(this)
+ );
},
- getInterfaces: function getInterfaces(name) {
- getInterfaces(name).then(function (result) {
- this.emit('getInterfaces', result);
- }.bind(this));
+ getInterfaces: function (name) {
+ getInterfaces(name).then(
+ function (result) {
+ this.emit("getInterfaces", result);
+ }.bind(this)
+ );
},
- setInitAction: function setInitAction(name, action) {
- _setInitAction(name, action).then(function (result) {
- this.emit('setInitAction', result);
- }.bind(this));
+ setInitAction: function (name, action) {
+ _setInitAction(name, action).then(
+ function (result) {
+ this.emit("setInitAction", result);
+ }.bind(this)
+ );
},
-}
+};
var status = baseclass.extend({
render: function () {
return Promise.all([
- L.resolveDefault(getInitStatus(), {}),
-// L.resolveDefault(getGateways(), {}),
+ L.resolveDefault(getInitStatus(pkg.Name), {}),
+ // L.resolveDefault(getGateways(pkg.Name), {}),
]).then(function (data) {
-// var replyStatus = data[0];
-// var replyGateways = data[1];
+ // var replyStatus = data[0];
+ // var replyGateways = data[1];
var reply;
var text;
if (data[0] && data[0][pkg.Name]) {
reply = data[0][pkg.Name];
- }
- else {
+ } else {
reply = {
enabled: null,
running: null,
running_iptables: null,
running_nft: null,
+ running_nft_file: null,
version: null,
gateways: null,
errors: [],
@@ -130,187 +141,351 @@ var status = baseclass.extend({
};
}
- var header = E('h2', {}, _("Policy Based Routing - Status"));
- var statusTitle = E('label', { class: 'cbi-value-title' }, _("Service Status"));
+ var header = E("h2", {}, _("Policy Based Routing - Status"));
+ var statusTitle = E(
+ "label",
+ { class: "cbi-value-title" },
+ _("Service Status")
+ );
if (reply.version) {
+ text = _("Version %s").format(reply.version) + " - ";
if (reply.running) {
+ text += _("Running");
if (reply.running_iptables) {
- text = _("Running (version: %s using iptables)").format(reply.version);
- }
- else if (reply.running_nft) {
- text = _("Running (version: %s using nft)").format(reply.version);
+ text += " (" + _("iptables mode") + ").";
+ } else if (reply.running_nft_file) {
+ text += " (" + _("fw4 nft file mode") + ").";
+ } else if (reply.running_nft) {
+ text += " (" + _("nft mode") + ").";
+ } else {
+ text += ".";
}
- else {
- text = _("Running (version: %s)").format(reply.version);
- }
- }
- else {
+ } else {
if (reply.enabled) {
- text = _("Stopped (version: %s)").format(reply.version);
- }
- else {
- text = _("Stopped (Disabled)");
+ text += _("Stopped.");
+ } else {
+ text += _("Stopped (Disabled).");
}
}
- }
- else {
+ } else {
text = _("Not installed or not found");
}
- var statusText = E('div', {}, text);
- var statusField = E('div', { class: 'cbi-value-field' }, statusText);
- var statusDiv = E('div', { class: 'cbi-value' }, [statusTitle, statusField]);
+ var statusText = E("div", {}, text);
+ var statusField = E("div", { class: "cbi-value-field" }, statusText);
+ var statusDiv = E("div", { class: "cbi-value" }, [
+ statusTitle,
+ statusField,
+ ]);
var gatewaysDiv = [];
if (reply.gateways) {
- var gatewaysTitle = E('label', { class: 'cbi-value-title' }, _("Service Gateways"));
- text = _("The %s indicates default gateway. See the %sREADME%s for details.").format("<strong>✓</strong>",
- "<a href=\"" + pkg.URL + "#a-word-about-default-routing \" target=\"_blank\">", "</a>")
- var gatewaysDescr = E('div', { class: 'cbi-value-description' }, text);
- var gatewaysText = E('div', {}, reply.gateways);
- var gatewaysField = E('div', { class: 'cbi-value-field' }, [gatewaysText, gatewaysDescr]);
- gatewaysDiv = E('div', { class: 'cbi-value' }, [gatewaysTitle, gatewaysField]);
+ var gatewaysTitle = E(
+ "label",
+ { class: "cbi-value-title" },
+ _("Service Gateways")
+ );
+ text = _(
+ "The %s indicates default gateway. See the %sREADME%s for details."
+ ).format(
+ "<strong>✓</strong>",
+ '<a href="' + pkg.URL + '#AWordAboutDefaultRouting" target="_blank">',
+ "</a>"
+ );
+ var gatewaysDescr = E("div", { class: "cbi-value-description" }, text);
+ var gatewaysText = E("div", {}, reply.gateways);
+ var gatewaysField = E("div", { class: "cbi-value-field" }, [
+ gatewaysText,
+ gatewaysDescr,
+ ]);
+ gatewaysDiv = E("div", { class: "cbi-value" }, [
+ gatewaysTitle,
+ gatewaysField,
+ ]);
}
var warningsDiv = [];
if (reply.warnings && reply.warnings.length) {
var textLabelsTable = {
- warningResolverNotSupported: _("Resolver set (%s) is not supported on this system.").format(uci.get(pkg.Name, 'config', 'resolver_set')),
- warningAGHVersionTooLow: _("Installed AdGuardHome (%s) doesn't support 'ipset_file' option."),
+ warningResolverNotSupported: _(
+ "Resolver set (%s) is not supported on this system."
+ ).format(L.uci.get(pkg.Name, "config", "resolver_set")),
+ warningAGHVersionTooLow: _(
+ "Installed AdGuardHome (%s) doesn't support 'ipset_file' option."
+ ),
warningPolicyProcessCMD: _("%s"),
- warningTorUnsetParams: _("Please unset 'src_addr', 'src_port' and 'dest_port' for policy '%s'"),
- warningTorUnsetProto: _("Please unset 'proto' or set 'proto' to 'all' for policy '%s'"),
- warningTorUnsetChainIpt: _("Please unset 'chain' or set 'chain' to 'PREROUTING' for policy '%s'"),
- warningTorUnsetChainNft: _("Please unset 'chain' or set 'chain' to 'prerouting' for policy '%s'"),
- warningInvalidOVPNConfig: _("Invalid OpenVPN config for %s interface"),
- warningOutdatedWebUIApp: _("The WebUI application is outdated (version %s), please update it"),
+ warningTorUnsetParams: _(
+ "Please unset 'src_addr', 'src_port' and 'dest_port' for policy '%s'"
+ ),
+ warningTorUnsetProto: _(
+ "Please unset 'proto' or set 'proto' to 'all' for policy '%s'"
+ ),
+ warningTorUnsetChainIpt: _(
+ "Please unset 'chain' or set 'chain' to 'PREROUTING' for policy '%s'"
+ ),
+ warningTorUnsetChainNft: _(
+ "Please unset 'chain' or set 'chain' to 'prerouting' for policy '%s'"
+ ),
+ warningInvalidOVPNConfig: _(
+ "Invalid OpenVPN config for %s interface"
+ ),
+ warningOutdatedWebUIApp: _(
+ "The WebUI application is outdated (version %s), please update it"
+ ),
+ warningBadNftCallsInUserFile: _(
+ "Incompatible nft calls detected in user include file, disabling fw4 nft file support."
+ ),
+ warningDnsmasqInstanceNoConfdir: _(
+ "Dnsmasq instance (%s) targeted in settings, but it doesn't have its own confdir."
+ ),
};
- var warningsTitle = E('label', { class: 'cbi-value-title' }, _("Service Warnings"));
+ var warningsTitle = E(
+ "label",
+ { class: "cbi-value-title" },
+ _("Service Warnings")
+ );
var text = "";
- (reply.warnings).forEach(element => {
+ reply.warnings.forEach((element) => {
if (element.id && textLabelsTable[element.id]) {
- if (element.id !== 'warningPolicyProcessCMD') {
- text += (textLabelsTable[element.id] + '.').format(element.extra || ' ') + "<br />";
+ if (element.id !== "warningPolicyProcessCMD") {
+ text +=
+ (textLabelsTable[element.id] + ".").format(
+ element.extra || " "
+ ) + "<br />";
}
- }
- else {
- text += _("Unknown Warning.") + "<br />";
+ } else {
+ text += _("Unknown warning") + "<br />";
}
});
- var warningsText = E('div', {}, text);
- var warningsField = E('div', { class: 'cbi-value-field' }, warningsText);
- warningsDiv = E('div', { class: 'cbi-value' }, [warningsTitle, warningsField]);
+ var warningsText = E("div", {}, text);
+ var warningsField = E(
+ "div",
+ { class: "cbi-value-field" },
+ warningsText
+ );
+ warningsDiv = E("div", { class: "cbi-value" }, [
+ warningsTitle,
+ warningsField,
+ ]);
}
var errorsDiv = [];
if (reply.errors && reply.errors.length) {
var textLabelsTable = {
- errorConfigValidation: _("Config (%s) validation failure").format('/etc/config/' + pkg.Name),
- errorNoIpFull: _("%s binary cannot be found").format('ip-full'),
- errorNoIptables: _("%s binary cannot be found").format('iptables'),
- errorNoIpset: _("Resolver set support (%s) requires ipset, but ipset binary cannot be found").format(uci.get(pkg.Name, 'config', 'resolver_set')),
- errorNoNft: _("Resolver set support (%s) requires nftables, but nft binary cannot be found").format(uci.get(pkg.Name, 'config', 'resolver_set')),
- errorResolverNotSupported: _("Resolver set (%s) is not supported on this system").format(uci.get(pkg.Name, 'config', 'resolver_set')),
- errorServiceDisabled: _("The %s service is currently disabled").format(pkg.Name),
- errorNoWanGateway: _("The %s service failed to discover WAN gateway").format(pkg.Name),
- errorIpsetNameTooLong: _("The ipset name '%s' is longer than allowed 31 characters"),
- errorNftsetNameTooLong: _("The nft set name '%s' is longer than allowed 31 characters"),
- errorUnexpectedExit: _("Unexpected exit or service termination: '%s'"),
- errorPolicyNoSrcDest: _("Policy '%s' has no source/destination parameters"),
+ errorConfigValidation: _("Config (%s) validation failure").format(
+ "/etc/config/" + pkg.Name
+ ),
+ errorNoIpFull: _("%s binary cannot be found").format("ip-full"),
+ errorNoIptables: _("%s binary cannot be found").format("iptables"),
+ errorNoIpset: _(
+ "Resolver set support (%s) requires ipset, but ipset binary cannot be found"
+ ).format(L.uci.get(pkg.Name, "config", "resolver_set")),
+ errorNoNft: _(
+ "Resolver set support (%s) requires nftables, but nft binary cannot be found"
+ ).format(L.uci.get(pkg.Name, "config", "resolver_set")),
+ errorResolverNotSupported: _(
+ "Resolver set (%s) is not supported on this system"
+ ).format(L.uci.get(pkg.Name, "config", "resolver_set")),
+ errorServiceDisabled: _(
+ "The %s service is currently disabled"
+ ).format(pkg.Name),
+ errorNoWanGateway: _(
+ "The %s service failed to discover WAN gateway"
+ ).format(pkg.Name),
+ errorIpsetNameTooLong: _(
+ "The ipset name '%s' is longer than allowed 31 characters"
+ ),
+ errorNftsetNameTooLong: _(
+ "The nft set name '%s' is longer than allowed 255 characters"
+ ),
+ errorUnexpectedExit: _(
+ "Unexpected exit or service termination: '%s'"
+ ),
+ errorPolicyNoSrcDest: _(
+ "Policy '%s' has no source/destination parameters"
+ ),
errorPolicyNoInterface: _("Policy '%s' has no assigned interface"),
- errorPolicyUnknownInterface: _("Policy '%s' has an unknown interface"),
+ errorPolicyUnknownInterface: _(
+ "Policy '%s' has an unknown interface"
+ ),
errorPolicyProcessCMD: _("%s"),
errorFailedSetup: _("Failed to set up '%s'"),
errorFailedReload: _("Failed to reload '%s'"),
errorUserFileNotFound: _("Custom user file '%s' not found or empty"),
errorUserFileSyntax: _("Syntax error in custom user file '%s'"),
errorUserFileRunning: _("Error running custom user file '%s'"),
- errorUserFileNoCurl: _("Use of 'curl' is detected in custom user file '%s', but 'curl' isn't installed"),
+ errorUserFileNoCurl: _(
+ "Use of 'curl' is detected in custom user file '%s', but 'curl' isn't installed"
+ ),
errorNoGateways: _("Failed to set up any gateway"),
- errorResolver: _("Resolver %s"),
- errorPolicyProcessNoIpv6: _("Skipping IPv6 policy '%s' as IPv6 support is disabled"),
- errorPolicyProcessUnknownFwmark: _("Unknown packet mark for interface '%s'"),
- errorPolicyProcessMismatchFamily: _("Mismatched IP family between in policy %s"),
- errorPolicyProcessUnknownProtocol: _("Unknown protocol in policy %s"),
- errorPolicyProcessInsertionFailed: _("Insertion failed for both IPv4 and IPv6 for policy %s"),
- errorPolicyProcessInsertionFailedIpv4: _("Insertion failed for IPv4 for policy %s"),
- errorInterfaceRoutingEmptyValues: _("Received empty tid/mark or interface name when setting up routing"),
- errorFailedToResolve: _("Failed to resolve %s"),
- errorInvalidOVPNConfig: _("Invalid OpenVPN config for %s interface"),
+ errorResolver: _("Resolver '%s'"),
+ errorPolicyProcessNoIpv6: _(
+ "Skipping IPv6 policy '%s' as IPv6 support is disabled"
+ ),
+ errorPolicyProcessUnknownFwmark: _(
+ "Unknown packet mark for interface '%s'"
+ ),
+ errorPolicyProcessMismatchFamily: _(
+ "Mismatched IP family between in policy '%s'"
+ ),
+ errorPolicyProcessUnknownProtocol: _(
+ "Unknown protocol in policy '%s'"
+ ),
+ errorPolicyProcessInsertionFailed: _(
+ "Insertion failed for both IPv4 and IPv6 for policy '%s'"
+ ),
+ errorPolicyProcessInsertionFailedIpv4: _(
+ "Insertion failed for IPv4 for policy '%s'"
+ ),
+ errorInterfaceRoutingEmptyValues: _(
+ "Received empty tid/mark or interface name when setting up routing"
+ ),
+ errorFailedToResolve: _("Failed to resolve '%s'"),
+ errorInvalidOVPNConfig: _(
+ "Invalid OpenVPN config for '%s' interface"
+ ),
+ errorNftFileInstall: _("Failed to install fw4 nft file '%s'"),
+ errorNoDownloadWithSecureReload: _(
+ "Policy '%s' refers to URL which can't be downloaded in 'secure_reload' mode!"
+ ),
+ errorDownloadUrlNoHttps: _(
+ "Failed to download '%s', HTTPS is not supported!"
+ ),
+ errorDownloadUrl: _("Failed to download '%s'!"),
+ errorFileSchemaRequiresCurl: _(
+ "The file:// schema requires curl, but it's not detected on this system!"
+ ),
};
- var errorsTitle = E('label', { class: 'cbi-value-title' }, _("Service Errors"));
+ var errorsTitle = E(
+ "label",
+ { class: "cbi-value-title" },
+ _("Service Errors")
+ );
var text = "";
- (reply.errors).forEach(element => {
+ reply.errors.forEach((element) => {
if (element.id && textLabelsTable[element.id]) {
- if (element.id !== 'errorPolicyProcessCMD') {
- text += (textLabelsTable[element.id] + '!').format(element.extra || ' ') + "<br />";
+ if (element.id !== "errorPolicyProcessCMD") {
+ text +=
+ (textLabelsTable[element.id] + "!").format(
+ element.extra || " "
+ ) + "<br />";
}
- }
- else {
- text += _("Unknown Error!") + "<br />";
+ } else {
+ text += _("Unknown error!") + "<br />";
}
});
- var errorsText = E('div', {}, text);
- var errorsField = E('div', { class: 'cbi-value-field' }, errorsText);
- errorsDiv = E('div', { class: 'cbi-value' }, [errorsTitle, errorsField]);
+ text += _("Errors encountered, please check the %sREADME%s!").format(
+ '<a href="' + pkg.URL + '" target="_blank">',
+ "</a><br />"
+ );
+ var errorsText = E("div", {}, text);
+ var errorsField = E("div", { class: "cbi-value-field" }, errorsText);
+ errorsDiv = E("div", { class: "cbi-value" }, [
+ errorsTitle,
+ errorsField,
+ ]);
}
- var btn_gap = E('span', {}, '&#160;&#160;');
- var btn_gap_long = E('span', {}, '&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;');
+ var btn_gap = E("span", {}, "&#160;&#160;");
+ var btn_gap_long = E(
+ "span",
+ {},
+ "&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;"
+ );
- 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_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_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_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_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'));
+ 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")
+ );
if (reply.enabled) {
btn_enable.disabled = true;
@@ -319,14 +494,12 @@ var status = baseclass.extend({
btn_start.disabled = true;
btn_action.disabled = false;
btn_stop.disabled = false;
- }
- else {
+ } else {
btn_start.disabled = false;
btn_action.disabled = true;
btn_stop.disabled = true;
}
- }
- else {
+ } else {
btn_start.disabled = true;
btn_action.disabled = true;
btn_stop.disabled = true;
@@ -334,22 +507,39 @@ var status = baseclass.extend({
btn_disable.disabled = true;
}
- var buttonsTitle = E('label', { class: 'cbi-value-title' }, _("Service Control"))
- var buttonsText = E('div', {}, [btn_start, btn_gap, btn_action, btn_gap, btn_stop, btn_gap_long, btn_enable, btn_gap, btn_disable]);
- var buttonsField = E('div', { class: 'cbi-value-field' }, buttonsText);
- if (reply.version) {
- var buttonsDiv = E('div', { class: 'cbi-value' }, [buttonsTitle, buttonsField]);
- }
- else {
- var buttonsDiv = [];
- }
-
- return E('div', {}, [header, statusDiv, gatewaysDiv, warningsDiv, errorsDiv, buttonsDiv]);
+ var buttonsTitle = E(
+ "label",
+ { class: "cbi-value-title" },
+ _("Service Control")
+ );
+ var buttonsText = E("div", {}, [
+ btn_start,
+ btn_gap,
+ btn_action,
+ btn_gap,
+ btn_stop,
+ btn_gap_long,
+ btn_enable,
+ btn_gap,
+ btn_disable,
+ ]);
+ var buttonsField = E("div", { class: "cbi-value-field" }, buttonsText);
+ var buttonsDiv = reply.version
+ ? E("div", { class: "cbi-value" }, [buttonsTitle, buttonsField])
+ : "";
+ return E("div", {}, [
+ header,
+ statusDiv,
+ gatewaysDiv,
+ warningsDiv,
+ errorsDiv,
+ buttonsDiv,
+ ]);
});
},
});
-RPC.on('setInitAction', function (reply) {
+RPC.on("setInitAction", function (reply) {
ui.hideModal();
location.reload();
});
@@ -357,5 +547,5 @@ RPC.on('setInitAction', function (reply) {
return L.Class.extend({
status: status,
getInterfaces: getInterfaces,
- getPlatformSupport: getPlatformSupport
+ getPlatformSupport: getPlatformSupport,
});
diff --git a/applications/luci-app-pbr/htdocs/luci-static/resources/view/pbr/overview.js b/applications/luci-app-pbr/htdocs/luci-static/resources/view/pbr/overview.js
index 2b5adaeb2e..99f8a502fa 100644
--- a/applications/luci-app-pbr/htdocs/luci-static/resources/view/pbr/overview.js
+++ b/applications/luci-app-pbr/htdocs/luci-static/resources/view/pbr/overview.js
@@ -1,280 +1,404 @@
// Copyright 2022 Stan Grishin <stangri@melmac.ca>
// This code wouldn't have been possible without help from [@vsviridov](https://github.com/vsviridov)
-'use strict';
-'require form';
-'require rpc';
-'require uci';
-'require view';
-'require pbr.status as pbr';
+"use strict";
+"require form";
+"require rpc";
+"require view";
+"require pbr.status as pbr";
var pkg = {
- get Name() { return 'pbr'; },
- get URL() { return 'https://docs.openwrt.melmac.net/' + pkg.Name + '/'; }
+ get Name() {
+ return "pbr";
+ },
+
+ get URL() {
+ return "https://docs.openwrt.melmac.net/" + pkg.Name + "/";
+ },
};
return view.extend({
load: function () {
return Promise.all([
- uci.load(pkg.Name)
+ L.resolveDefault(pbr.getInterfaces(pkg.Name), {}),
+ L.resolveDefault(pbr.getPlatformSupport(pkg.Name), {}),
+ L.resolveDefault(L.uci.load(pkg.Name), {}),
]);
},
- render: function () {
- return Promise.all([
- L.resolveDefault(pbr.getInterfaces(), {}),
- L.resolveDefault(pbr.getPlatformSupport(), {}),
- ]).then(function (data) {
- var arrInterfaces;
- var replyPlatform;
- var status, m, s, o;
-
- if (data[0] && data[0][pkg.Name] && data[0][pkg.Name].interfaces) {
- arrInterfaces = data[0][pkg.Name].interfaces;
- }
- else {
- arrInterfaces = ["wan"];
- }
-
- if (data[1] && data[1][pkg.Name]) {
- replyPlatform = data[1][pkg.Name];
- }
- else {
- replyPlatform = {
- ipset_installed: null,
- nft_installed: null,
- adguardhome_installed: null,
- dnsmasq_installed: null,
- unbound_installed: null,
- adguardhome_ipset_support: null,
- dnsmasq_ipset_support: null,
- dnsmasq_nftset_support: null,
- };
- }
-
- status = new pbr.status();
- m = new form.Map(pkg.Name, _("Policy Based Routing - Configuration"));
-
- s = m.section(form.NamedSection, 'config', pkg.Name);
- s.tab("tab_basic", _("Basic Configuration"));
- s.tab("tab_advanced", _("Advanced Configuration"),
- _("%sWARNING:%s Please make sure to check the %sREADME%s before changing anything in this section! " +
- "Change any of the settings below with extreme caution!%s").format(
- "<br/>&#160;&#160;&#160;&#160;<b>", "</b>",
- "<a href=\"" + pkg.URL + "#service-configuration-settings\" target=\"_blank\">", "</a>", "<br/><br/>"));
- s.tab("tab_webui", _("Web UI Configuration"))
-
- o = s.taboption("tab_basic", form.ListValue, "verbosity", _("Output verbosity"),
- _("Controls both system log and console output verbosity."));
- o.value("0", _("Suppress/No output"));
- o.value("1", _("Condensed output"));
- o.value("2", _("Verbose output"));
- o.default = "2";
-
- o = s.taboption("tab_basic", form.ListValue, "strict_enforcement", _("Strict enforcement"),
- _("See the %sREADME%s for details.").format(
- "<a href=\"" + pkg.URL + "#strict-enforcement\" target=\"_blank\">", "</a>"));
- o.value("0", _("Do not enforce policies when their gateway is down"));
- o.value("1", _("Strictly enforce policies when their gateway is down"));
- o.default = "1";
-
- var text = "";
- if (replyPlatform.adguardhome_ipset_support === null) {
- text += _("The %s support is unknown.").format("<i>adguardhome.ipset</i>") + "<br />"
- }
- else if (!(replyPlatform.adguardhome_ipset_support)) {
- text += _("The %s is not supported on this system.").format("<i>adguardhome.ipset</i>") + "<br />"
- }
- if (replyPlatform.dnsmasq_ipset_support === null) {
- text += _("The %s support is unknown.").format("<i>dnsmasq.ipset</i>") + "<br />"
- }
- else if (!(replyPlatform.dnsmasq_ipset_support)) {
- text += _("The %s is not supported on this system.").format("<i>dnsmasq.ipset</i>") + "<br />"
- }
- if (replyPlatform.dnsmasq_nftset_support === null) {
- text += _("The %s support is unknown.").format("<i>dnsmasq.nftset</i>") + "<br />"
- }
- else if (!(replyPlatform.dnsmasq_nftset_support)) {
- text += _("The %s is not supported on this system.").format("<i>dnsmasq.nftset</i>") + "<br />"
- }
- text += _("Please check the %sREADME%s before changing this option.").format(
- "<a href=\"" + pkg.URL + "#use-resolvers-set-support\" target=\"_blank\">", "</a>");
- o = s.taboption("tab_basic", form.ListValue, "resolver_set", _("Use resolver set support for domains"), text);
- o.value("none", _("Disabled"));
- if (replyPlatform.adguardhome_ipset_support) {
- o.value("adguardhome.ipset", _("AdGuardHome ipset"));
- o.default = ("adguardhome.ipset", _("AdGuardHome ipset"));
- }
- if (replyPlatform.dnsmasq_ipset_support) {
- o.value("dnsmasq.ipset", _("Dnsmasq ipset"));
- o.default = ("dnsmasq.ipset", _("Dnsmasq ipset"));
- }
- if (replyPlatform.dnsmasq_nftset_support) {
- o.value("dnsmasq.nftset", _("Dnsmasq nft set"));
- o.default = ("dnsmasq.nftset", _("Dnsmasq nft set"));
+ render: function (data) {
+ var status, m, s, o;
+ var reply = {
+ interfaces: (data[0] &&
+ data[0][pkg.Name] &&
+ data[0][pkg.Name].interfaces) || ["wan"],
+ platform: (data[1] && data[1][pkg.Name]) || {
+ ipset_installed: null,
+ nft_installed: null,
+ adguardhome_installed: null,
+ dnsmasq_installed: null,
+ unbound_installed: null,
+ adguardhome_ipset_support: null,
+ dnsmasq_ipset_support: null,
+ dnsmasq_nftset_support: null,
+ },
+ };
+
+ status = new pbr.status();
+ m = new form.Map(pkg.Name, _("Policy Based Routing - Configuration"));
+
+ s = m.section(form.NamedSection, "config", pkg.Name);
+ s.tab("tab_basic", _("Basic Configuration"));
+ s.tab(
+ "tab_advanced",
+ _("Advanced Configuration"),
+ _(
+ "%sWARNING:%s Please make sure to check the %sREADME%s before changing anything in this section! " +
+ "Change any of the settings below with extreme caution!%s"
+ ).format(
+ "<br/>&#160;&#160;&#160;&#160;<b>",
+ "</b>",
+ '<a href="' +
+ pkg.URL +
+ '#ServiceConfigurationSettings" target="_blank">',
+ "</a>",
+ "<br/><br/>"
+ )
+ );
+
+ s.tab("tab_webui", _("Web UI Configuration"));
+
+ o = s.taboption(
+ "tab_basic",
+ form.ListValue,
+ "verbosity",
+ _("Output verbosity"),
+ _("Controls both system log and console output verbosity.")
+ );
+ o.value("0", _("Suppress/No output"));
+ o.value("1", _("Condensed output"));
+ o.value("2", _("Verbose output"));
+ o.default = "2";
+
+ o = s.taboption(
+ "tab_basic",
+ form.ListValue,
+ "strict_enforcement",
+ _("Strict enforcement"),
+ _("See the %sREADME%s for details.").format(
+ '<a href="' + pkg.URL + '#StrictEnforcement" target="_blank">',
+ "</a>"
+ )
+ );
+ o.value("0", _("Do not enforce policies when their gateway is down"));
+ o.value("1", _("Strictly enforce policies when their gateway is down"));
+ o.default = "1";
+
+ var text = "";
+ if (reply.platform.adguardhome_ipset_support === null) {
+ text +=
+ _("The %s support is unknown.").format("<i>adguardhome.ipset</i>") +
+ "<br />";
+ } else if (!reply.platform.adguardhome_ipset_support) {
+ text +=
+ _("The %s is not supported on this system.").format(
+ "<i>adguardhome.ipset</i>"
+ ) + "<br />";
+ }
+ if (reply.platform.dnsmasq_ipset_support === null) {
+ text +=
+ _("The %s support is unknown.").format("<i>dnsmasq.ipset</i>") +
+ "<br />";
+ } else if (!reply.platform.dnsmasq_ipset_support) {
+ text +=
+ _("The %s is not supported on this system.").format(
+ "<i>dnsmasq.ipset</i>"
+ ) + "<br />";
+ }
+ if (reply.platform.dnsmasq_nftset_support === null) {
+ text +=
+ _("The %s support is unknown.").format("<i>dnsmasq.nftset</i>") +
+ "<br />";
+ } else if (!reply.platform.dnsmasq_nftset_support) {
+ text +=
+ _("The %s is not supported on this system.").format(
+ "<i>dnsmasq.nftset</i>"
+ ) + "<br />";
+ }
+ text += _(
+ "Please check the %sREADME%s before changing this option."
+ ).format(
+ '<a href="' + pkg.URL + '#UseResolversSetSupport" target="_blank">',
+ "</a>"
+ );
+
+ o = s.taboption(
+ "tab_basic",
+ form.ListValue,
+ "resolver_set",
+ _("Use resolver set support for domains"),
+ text
+ );
+ o.value("none", _("Disabled"));
+ if (reply.platform.adguardhome_ipset_support) {
+ o.value("adguardhome.ipset", _("AdGuardHome ipset"));
+ o.default = "adguardhome.ipset";
+ }
+ if (reply.platform.dnsmasq_ipset_support) {
+ o.value("dnsmasq.ipset", _("Dnsmasq ipset"));
+ o.default = "dnsmasq.ipset";
+ }
+ if (reply.platform.dnsmasq_nftset_support) {
+ o.value("dnsmasq.nftset", _("Dnsmasq nft set"));
+ o.default = "dnsmasq.nftset";
+ }
+
+ o = s.taboption(
+ "tab_basic",
+ form.ListValue,
+ "ipv6_enabled",
+ _("IPv6 Support")
+ );
+ o.value("0", _("Disabled"));
+ o.value("1", _("Enabled"));
+
+ o = s.taboption(
+ "tab_advanced",
+ form.DynamicList,
+ "supported_interface",
+ _("Supported Interfaces"),
+ _(
+ "Allows to specify the list of interface names (in lower case) to be explicitly supported by the service. " +
+ "Can be useful if your OpenVPN tunnels have dev option other than tun* or tap*."
+ )
+ );
+ o.optional = false;
+
+ o = s.taboption(
+ "tab_advanced",
+ form.DynamicList,
+ "ignored_interface",
+ _("Ignored Interfaces"),
+ _(
+ "Allows to specify the list of interface names (in lower case) to be ignored by the service. " +
+ "Can be useful if running both VPN server and VPN client on the router."
+ )
+ );
+ o.optional = false;
+
+ o = s.taboption(
+ "tab_advanced",
+ form.ListValue,
+ "rule_create_option",
+ _("Rule Create option"),
+ _("Select Add for -A/add and Insert for -I/Insert.")
+ );
+ o.value("add", _("Add"));
+ o.value("insert", _("Insert"));
+ o.default = "add";
+
+ o = s.taboption(
+ "tab_advanced",
+ form.ListValue,
+ "icmp_interface",
+ _("Default ICMP Interface"),
+ _("Force the ICMP protocol interface.")
+ );
+ o.value("", _("No Change"));
+ reply.interfaces.forEach((element) => {
+ if (element.toLowerCase() !== "ignore") {
+ o.value(element);
}
-
- o = s.taboption("tab_basic", form.ListValue, "ipv6_enabled", _("IPv6 Support"));
- o.value("0", _("Disabled"));
- o.value("1", _("Enabled"));
-
- o = s.taboption("tab_advanced", form.DynamicList, "supported_interface", _("Supported Interfaces"),
- _("Allows to specify the list of interface names (in lower case) to be explicitly supported by the service. " +
- "Can be useful if your OpenVPN tunnels have dev option other than tun* or tap*."));
- o.optional = false;
-
- o = s.taboption("tab_advanced", form.DynamicList, "ignored_interface", _("Ignored Interfaces"),
- _("Allows to specify the list of interface names (in lower case) to be ignored by the service. " +
- "Can be useful if running both VPN server and VPN client on the router."));
- o.optional = false;
-
- o = s.taboption("tab_advanced", form.ListValue, "rule_create_option", _("Rule Create option"),
- _("Select Add for -A/add and Insert for -I/Insert."));
- o.value("add", _("Add"));
- o.value("insert", _("Insert"));
- o.default = "add";
-
- o = s.taboption("tab_advanced", form.ListValue, "icmp_interface", _("Default ICMP Interface"),
- _("Force the ICMP protocol interface."));
- o.value("", _("No Change"));
- arrInterfaces.forEach(element => {
- if (element.toLowerCase() !== "ignore") {
- o.value(element);
- }
- });
- o.rmempty = true;
-
- o = s.taboption("tab_advanced", form.Value, "wan_tid", _("WAN Table ID"),
- _("Starting (WAN) Table ID number for tables created by the service."));
- o.rmempty = true;
- o.placeholder = "201";
- o.datatype = "and(uinteger, min(201))";
-
- o = s.taboption("tab_advanced", form.Value, "wan_mark", _("WAN Table FW Mark"),
- _("Starting (WAN) FW Mark for marks used by the service. High starting mark is " +
- "used to avoid conflict with SQM/QoS. Change with caution together with") +
- " " + _("Service FW Mask") + ".");
- o.rmempty = true;
- o.placeholder = "010000";
- o.datatype = "hexstring";
-
- o = s.taboption("tab_advanced", form.Value, "fw_mask", _("Service FW Mask"),
- _("FW Mask used by the service. High mask is used to avoid conflict with SQM/QoS. " +
- "Change with caution together with") + " " + _("WAN Table FW Mark") + ".");
- o.rmempty = true;
- o.placeholder = "ff0000";
- o.datatype = "hexstring";
-
- o = s.taboption("tab_webui", form.ListValue, "webui_show_ignore_target", _("Add Ignore Target"),
- _("Adds 'ignore' to the list of interfaces for policies. See the %sREADME%s for details.").format(
- "<a href=\"" + pkg.URL + "#ignore-target\" target=\"_blank\">", "</a>"));
- o.value("0", _("Disabled"))
- o.value("1", _("Enabled"))
- o.default = "0";
- o.optional = false;
-
- o = s.taboption("tab_webui", form.DynamicList, "webui_supported_protocol", _("Supported Protocols"),
- _("Display these protocols in protocol column in Web UI."));
- o.optional = false;
-
- s = m.section(form.GridSection, 'policy', _('Policies'),
- _("Name, interface and at least one other field are required. Multiple local and remote " +
+ });
+ o.rmempty = true;
+
+ o = s.taboption(
+ "tab_advanced",
+ form.Value,
+ "wan_mark",
+ _("WAN Table FW Mark"),
+ _(
+ "Starting (WAN) FW Mark for marks used by the service. High starting mark is " +
+ "used to avoid conflict with SQM/QoS. Change with caution together with"
+ ) +
+ " " +
+ _("Service FW Mask") +
+ "."
+ );
+ o.rmempty = true;
+ o.placeholder = "010000";
+ o.datatype = "hexstring";
+
+ o = s.taboption(
+ "tab_advanced",
+ form.Value,
+ "fw_mask",
+ _("Service FW Mask"),
+ _(
+ "FW Mask used by the service. High mask is used to avoid conflict with SQM/QoS. " +
+ "Change with caution together with"
+ ) +
+ " " +
+ _("WAN Table FW Mark") +
+ "."
+ );
+ o.rmempty = true;
+ o.placeholder = "ff0000";
+ o.datatype = "hexstring";
+
+ o = s.taboption(
+ "tab_webui",
+ form.ListValue,
+ "webui_show_ignore_target",
+ _("Add Ignore Target"),
+ _(
+ "Adds 'ignore' to the list of interfaces for policies. See the %sREADME%s for details."
+ ).format(
+ '<a href="' + pkg.URL + '#IgnoreTarget" target="_blank">',
+ "</a>"
+ )
+ );
+ o.value("0", _("Disabled"));
+ o.value("1", _("Enabled"));
+ o.default = "0";
+ o.optional = false;
+
+ o = s.taboption(
+ "tab_webui",
+ form.DynamicList,
+ "webui_supported_protocol",
+ _("Supported Protocols"),
+ _("Display these protocols in protocol column in Web UI.")
+ );
+ o.optional = false;
+
+ s = m.section(
+ form.GridSection,
+ "policy",
+ _("Policies"),
+ _(
+ "Name, interface and at least one other field are required. Multiple local and remote " +
"addresses/devices/domains and ports can be space separated. Placeholders below represent just " +
- "the format/syntax and will not be used if fields are left blank."));
- s.rowcolors = true;
- s.sortable = true;
- s.anonymous = true;
- s.addremove = true;
-
- o = s.option(form.Flag, "enabled", _("Enabled"));
- o.default = "1";
- o.editable = true;
-
- o = s.option(form.Value, "name", _("Name"));
-
- o = s.option(form.Value, "src_addr", _("Local addresses / devices"));
- o.datatype = "list(neg(or(cidr,host,ipmask,ipaddr,macaddr,network)))";
- o.rmempty = true;
- o.default = "";
-
- o = s.option(form.Value, "src_port", _("Local ports"));
- o.datatype = "list(neg(or(portrange,port)))";
- o.placeholder = "0-65535";
- o.rmempty = true;
- o.default = "";
-
- o = s.option(form.Value, "dest_addr", _("Remote addresses / domains"));
- o.datatype = "list(neg(or(cidr,host,ipmask,ipaddr,macaddr,network)))";
- o.rmempty = true;
- o.default = "";
-
- o = s.option(form.Value, "dest_port", _("Remote ports"));
- o.datatype = "list(neg(or(portrange,port)))";
- o.placeholder = "0-65535";
- o.rmempty = true;
- o.default = "";
-
- o = s.option(form.ListValue, "proto", _("Protocol"));
- var proto = L.toArray(uci.get(pkg.Name, "config", "webui_supported_protocol"));
- if (!proto.length) {
- proto = ["all", "tcp", "udp", "tcp udp", "icmp"]
+ "the format/syntax and will not be used if fields are left blank."
+ )
+ );
+ s.rowcolors = true;
+ s.sortable = true;
+ s.anonymous = true;
+ s.addremove = true;
+
+ o = s.option(form.Flag, "enabled", _("Enabled"));
+ o.default = "1";
+ o.editable = true;
+
+ o = s.option(form.Value, "name", _("Name"));
+
+ o = s.option(form.Value, "src_addr", _("Local addresses / devices"));
+ o.datatype =
+ "list(neg(or(cidr,host,ipmask,ipaddr,macaddr,network,string)))";
+ o.rmempty = true;
+ o.default = "";
+
+ o = s.option(form.Value, "src_port", _("Local ports"));
+ o.datatype = "list(neg(or(portrange,port)))";
+ o.placeholder = "0-65535";
+ o.rmempty = true;
+ o.default = "";
+
+ o = s.option(form.Value, "dest_addr", _("Remote addresses / domains"));
+ o.datatype =
+ "list(neg(or(cidr,host,ipmask,ipaddr,macaddr,network,string)))";
+ o.rmempty = true;
+ o.default = "";
+
+ o = s.option(form.Value, "dest_port", _("Remote ports"));
+ o.datatype = "list(neg(or(portrange,port)))";
+ o.placeholder = "0-65535";
+ o.rmempty = true;
+ o.default = "";
+
+ o = s.option(form.ListValue, "proto", _("Protocol"));
+ var proto = L.toArray(
+ L.uci.get(pkg.Name, "config", "webui_supported_protocol")
+ );
+ if (!proto.length) {
+ proto = ["all", "tcp", "udp", "tcp udp", "icmp"];
+ }
+ proto.forEach((element) => {
+ if (element === "all") {
+ o.value("", _("all"));
+ o.default = "";
+ } else {
+ o.value(element.toLowerCase());
}
- proto.forEach(element => {
- if (element === "all") {
- o.value("", _("all"));
- o.default = ("", _("all"));
- }
- else {
- o.value(element.toLowerCase());
- }
- });
- o.rmempty = true;
-
- o = s.option(form.ListValue, "chain", _("Chain"));
- o.value("", "prerouting");
- o.value("forward", "forward");
- o.value("input", "input");
- o.value("output", "output");
- o.value("postrouting", "postrouting");
- o.default = ("", "prerouting");
- o.rmempty = true;
-
- o = s.option(form.ListValue, "interface", _("Interface"));
- arrInterfaces.forEach(element => {
- o.value(element);
- });
- o.datatype = "network";
- o.rmempty = false;
-
- s = m.section(form.NamedSection, 'config', pkg.Name, _("DSCP Tagging"),
- _("Set DSCP tags (in range between 1 and 63) for specific interfaces. See the %sREADME%s for details.").format(
- "<a href=\"" + pkg.URL + "#dscp-tag-based-policies" + "\" target=\"_blank\">", "</a>"));
- arrInterfaces.forEach(element => {
- if (element.toLowerCase() !== "ignore") {
- o = s.option(form.Value, element + "_dscp", element.toUpperCase() + " " + _("DSCP Tag"));
- o.datatype = "and(uinteger, min(1), max(63))";
- }
- });
-
- s = m.section(form.GridSection, 'include', _("Custom User File Includes"),
- _("Run the following user files after setting up but before restarting DNSMASQ. " +
- "See the %sREADME%s for details.").format(
- "<a href=\"" + pkg.URL + "#custom-user-files\" target=\"_blank\">", "</a>"));
- s.sortable = true;
- s.anonymous = true;
- s.addremove = true;
-
- o = s.option(form.Flag, "enabled", _("Enabled"));
- o.optional = false;
- o.editable = true;
- o.rmempty = false;
-
- o = s.option(form.Value, "path", _("Path"));
- o.optional = false;
- o.editable = true;
- o.rmempty = false;
-
- return Promise.all([status.render(), m.render()]);
- })
- }
+ });
+ o.rmempty = true;
+
+ o = s.option(form.ListValue, "chain", _("Chain"));
+ o.value("", "prerouting");
+ o.value("forward", "forward");
+ o.value("input", "input");
+ o.value("output", "output");
+ o.value("postrouting", "postrouting");
+ o.default = "";
+ o.rmempty = true;
+
+ o = s.option(form.ListValue, "interface", _("Interface"));
+ reply.interfaces.forEach((element) => {
+ o.value(element);
+ });
+ o.datatype = "network";
+ o.rmempty = false;
+
+ s = m.section(
+ form.NamedSection,
+ "config",
+ pkg.Name,
+ _("DSCP Tagging"),
+ _(
+ "Set DSCP tags (in range between 1 and 63) for specific interfaces. See the %sREADME%s for details."
+ ).format(
+ '<a href="' + pkg.URL + "#DSCPTag-BasedPolicies" + '" target="_blank">',
+ "</a>"
+ )
+ );
+ reply.interfaces.forEach((element) => {
+ if (element.toLowerCase() !== "ignore") {
+ o = s.option(
+ form.Value,
+ element + "_dscp",
+ element.toUpperCase() + " " + _("DSCP Tag")
+ );
+ o.datatype = "and(uinteger, min(1), max(63))";
+ }
+ });
+
+ s = m.section(
+ form.GridSection,
+ "include",
+ _("Custom User File Includes"),
+ _(
+ "Run the following user files after setting up but before restarting DNSMASQ. " +
+ "See the %sREADME%s for details."
+ ).format(
+ '<a href="' + pkg.URL + '#CustomUserFiles" target="_blank">',
+ "</a>"
+ )
+ );
+ s.sortable = true;
+ s.anonymous = true;
+ s.addremove = true;
+
+ o = s.option(form.Flag, "enabled", _("Enabled"));
+ o.optional = false;
+ o.editable = true;
+ o.rmempty = false;
+
+ o = s.option(form.Value, "path", _("Path"));
+ o.optional = false;
+ o.editable = true;
+ o.rmempty = false;
+
+ return Promise.all([status.render(), m.render()]);
+ },
});
diff --git a/applications/luci-app-pbr/htdocs/luci-static/resources/view/status/include/72_pbr.js b/applications/luci-app-pbr/htdocs/luci-static/resources/view/status/include/72_pbr.js
new file mode 100644
index 0000000000..536c3983c3
--- /dev/null
+++ b/applications/luci-app-pbr/htdocs/luci-static/resources/view/status/include/72_pbr.js
@@ -0,0 +1,88 @@
+"require ui";
+"require rpc";
+"require form";
+"require baseclass";
+
+var pkg = {
+ get Name() {
+ return "pbr";
+ },
+ get URL() {
+ return "https://docs.openwrt.melmac.net/" + pkg.Name + "/";
+ },
+};
+
+var getInitStatus = rpc.declare({
+ object: "luci." + pkg.Name,
+ method: "getInitStatus",
+ params: ["name"],
+});
+
+return baseclass.extend({
+ title: _("Policy Based Routing"),
+
+ load: function () {
+ return Promise.all([getInitStatus(pkg.Name)]);
+ },
+
+ render: function (data) {
+ var reply;
+ if (data[0] && data[0][pkg.Name]) {
+ reply = data[0][pkg.Name];
+ } else {
+ reply = {
+ enabled: null,
+ running: null,
+ running_iptables: null,
+ running_nft: null,
+ running_nft_file: null,
+ version: null,
+ gateways: null,
+ errors: [],
+ warnings: [],
+ };
+ }
+
+ var versionText,
+ statusText = "",
+ modeText = "";
+ if (reply.version) {
+ versionText = reply.version;
+ if (reply.running) {
+ statusText = _("Active");
+ if (reply.running_iptables) {
+ modeText = _("iptables mode");
+ } else if (reply.running_nft_file) {
+ modeText = _("fw4 nft file mode");
+ } else if (reply.running_nft) {
+ modeText = _("nft mode");
+ } else {
+ modeText = _("unknown");
+ }
+ } else {
+ if (reply.enabled) {
+ statusText = _("Inactive");
+ } else {
+ statusText = _("Inactive (Disabled)");
+ }
+ }
+ } else {
+ versionText = _("Not installed or not found");
+ }
+
+ var table = E("table", { class: "table", id: "pbr_status_table" }, [
+ E("tr", { class: "tr table-titles" }, [
+ E("th", { class: "th" }, _("Status")),
+ E("th", { class: "th" }, _("Version")),
+ E("th", { class: "th" }, _("Mode")),
+ ]),
+ E("tr", { class: "tr" }, [
+ E("td", { class: "td" }, statusText),
+ E("td", { class: "td" }, versionText),
+ E("td", { class: "td" }, modeText),
+ ]),
+ ]);
+
+ return table;
+ },
+});