Firewall: Rules [new]: Reduce complexity in url hash handling and when using firewall_rule_lookup (#9773)

* Reduce complexity of firewall_rule_lookup, we have an all rules entrypoint now, so potentially we could just search for the UUID of the rule without concerning us with interfaces anymore

* Clean up URL hash logic, we only allow #search and #interface now and need no special handling

* Only get the hash once, use it everywhere, re-add missing null fallback and initialized interface variable

* The hash was consumed too early now, fix it by shifting to the new spot where the variable is used last
This commit is contained in:
Monviech 2026-02-16 09:30:40 +01:00 committed by GitHub
parent 7738d7e865
commit d976ae7b6b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 8 additions and 29 deletions

View file

@ -65,8 +65,7 @@
}
// read interface from URL hash once, for the first grid load
const hashMatchInterface = window.location.hash.match(/(?:^#|&)interface=([^&]+)/);
let pendingUrlInterface = hashMatchInterface ? decodeURIComponent(hashMatchInterface[1]) : null;
let pendingUrlInterface = getUrlHash('interface') || null;
// Lives outside the grid, so the logic of the response handler can be changed after grid initialization
function dynamicResponseHandler(resp) {
@ -155,7 +154,6 @@
responsive: true,
sorting: false,
initialSearchPhrase: getUrlHash('search'),
triggerEditFor: getUrlHash('edit'),
requestHandler: function(request){
// Add category selectpicker
if ( $('#category_filter').val().length > 0) {
@ -165,7 +163,6 @@
let selectedInterface = $('#interface_select').val();
if (selectedInterface == null && pendingUrlInterface != null) {
selectedInterface = pendingUrlInterface;
pendingUrlInterface = null; // consume the hash so it is not used again
}
if (selectedInterface === '__floating') {
request.interface = '';
@ -797,20 +794,13 @@
},
false,
function (data) { // post_callback, apply the URL hash logic
const match = window.location.hash.match(/^#interface=([^&]+)/);
if (match) {
const ifaceFromHash = decodeURIComponent(match[1]);
const allOptions = Object.values(data).flatMap(group => group.items.map(i => i.value));
if (allOptions.includes(ifaceFromHash)) {
$('#interface_select').val(ifaceFromHash).selectpicker('refresh');
}
} else {
// Default to ALL interfaces
$('#interface_select').selectpicker('val', '__any');
}
const $select = $('#interface_select');
$select.selectpicker('val', pendingUrlInterface && $select.find(`option[value="${pendingUrlInterface}"]`).length
? pendingUrlInterface
: '__any' // Default view when having an invalid interface in hash
);
interfaceInitialized = true;
pendingUrlInterface = null; // consume the hash so it is not used again
},
true // render_html to show counts as badges
);

View file

@ -55,19 +55,8 @@ if ($_SERVER['REQUEST_METHOD'] === 'GET') {
header(url_safe('Location: /%s?if=%s&id=%s', [$parts['path'], $query['if'], $query['id']]));
}
} else {
// search model firewall rule
$interface = '';
$node = (new Filter())->getNodeByReference('rules.rule.' . $rid);
if ($node !== null) {
$interfaceValue = $node->interface->getValue();
// multiple interfaces in a rule are skipped as empty string is the default for floating
if ($interfaceValue !== '' && strpos($interfaceValue, ',') === false) {
$interface = $interfaceValue;
}
}
$base = strtok($rule->getRef(), '#');
$hash = url_safe('interface=%s&edit=%s', [$interface, $rid]);
$hash = url_safe('search=%s', [$rid]);
header("Location: /{$base}#{$hash}");
}
exit;