treewide: switch firewall zone, network and iface lists to dropdown code

Also switch the weekday and monthday lists in the firewall rule details to
cbi dropdowns, vastly uncluttering the form.

Signed-off-by: Jo-Philipp Wich <jo@mein.io>
This commit is contained in:
Jo-Philipp Wich 2018-06-08 08:19:20 +02:00
parent 9d48490729
commit 74be6f3974
9 changed files with 190 additions and 180 deletions

View file

@ -55,6 +55,7 @@ o = s:option(Value, "src", translate("Source zone"))
o.nocreate = true o.nocreate = true
o.default = "wan" o.default = "wan"
o.template = "cbi/firewall_zonelist" o.template = "cbi/firewall_zonelist"
o.rmempty = false
o = s:option(DynamicList, "src_mac", o = s:option(DynamicList, "src_mac",

View file

@ -255,7 +255,7 @@ else
o = s:option(Value, "src", translate("Source zone")) o = s:option(Value, "src", translate("Source zone"))
o.nocreate = true o.nocreate = true
o.allowany = true o.allowany = true
o.default = "wan" o.allowlocal = "src"
o.template = "cbi/firewall_zonelist" o.template = "cbi/firewall_zonelist"
@ -282,11 +282,21 @@ else
o.placeholder = translate("any") o.placeholder = translate("any")
o = s:option(Value, "dest", translate("Destination zone")) o = s:option(Value, "dest_local", translate("Output zone"))
o.nocreate = true
o.allowany = true
o.rmempty = false
o.template = "cbi/firewall_zonelist"
o.alias = "dest"
o:depends("src", "")
o = s:option(Value, "dest_remote", translate("Destination zone"))
o.nocreate = true o.nocreate = true
o.allowany = true o.allowany = true
o.allowlocal = true o.allowlocal = true
o.template = "cbi/firewall_zonelist" o.template = "cbi/firewall_zonelist"
o.alias = "dest"
o:depends({["src"] = "", ["!reverse"] = true})
o = s:option(Value, "dest_ip", translate("Destination address")) o = s:option(Value, "dest_ip", translate("Destination address"))
@ -316,9 +326,9 @@ else
translate("Passes additional arguments to iptables. Use with care!")) translate("Passes additional arguments to iptables. Use with care!"))
end end
o = s:option(MultiValue, "weekdays", translate("Week Days")) o = s:option(DropDown, "weekdays", translate("Week Days"))
o.oneline = true o.multiple = true
o.widget = "checkbox" o.display = 5
o:value("Sun", translate("Sunday")) o:value("Sun", translate("Sunday"))
o:value("Mon", translate("Monday")) o:value("Mon", translate("Monday"))
o:value("Tue", translate("Tuesday")) o:value("Tue", translate("Tuesday"))
@ -327,9 +337,9 @@ o:value("Thu", translate("Thursday"))
o:value("Fri", translate("Friday")) o:value("Fri", translate("Friday"))
o:value("Sat", translate("Saturday")) o:value("Sat", translate("Saturday"))
o = s:option(MultiValue, "monthdays", translate("Month Days")) o = s:option(DropDown, "monthdays", translate("Month Days"))
o.oneline = true o.multiple = true
o.widget = "checkbox" o.display = 15
for i = 1,31 do for i = 1,31 do
o:value(translate(i)) o:value(translate(i))
end end

View file

@ -101,9 +101,12 @@ end
function net.write(self, section, value) function net.write(self, section, value)
zone:clear_networks() zone:clear_networks()
local n local net
for n in ut.imatch(value) do for net in ut.imatch(value) do
zone:add_network(n) local n = nw:get_network(net) or nw:add_network(net, { proto = "none" })
if n then
zone:add_network(n:name())
end
end end
end end

View file

@ -24,26 +24,42 @@
end end
-%> -%>
<span> <div class="cbi-dropdown" dropdown-items="5" placeholder="<%:-- please select -- %>"<%=
<ul style="margin:0; list-style-type:none; text-align:left"> attr("name", cbid) ..
ifattr(self.widget == "checkbox", "multiple", "multiple") ..
ifattr(self.rmempty or self.optional, "optional", "optional")
%>>
<script type="item-template"><!--
<li value="{{value}}">
<span class="zonebadge" style="background:repeating-linear-gradient(45deg,rgba(204,204,204,0.5),rgba(204,204,204,0.5) 5px,rgba(255,255,255,0.5) 5px,rgba(255,255,255,0.5) 10px)">
<strong>{{value}}:</strong><em>(<%:create%>)</em>
</span>
</li>
--></script>
<ul>
<% if self.allowlocal then %> <% if self.allowlocal then %>
<li style="padding:0.5em"> <li value=""<%=ifattr(checked[""], "selected", "selected")%>>
<input class="cbi-input-radio" data-update="click change"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "_empty") .. attr("name", cbid) .. attr("value", "") .. ifattr(checked[""], "checked", "checked")%> /> &#160; <span style="background-color:<%=fwm.zone.get_color()%>" class="zonebadge">
<label<%=attr("for", cbid .. "_empty")%>></label>
<label<%=attr("for", cbid .. "_empty")%> style="background-color:<%=fwm.zone.get_color()%>" class="zonebadge">
<strong><%:Device%></strong> <strong><%:Device%></strong>
<% if self.allowany and self.allowlocal then %>(<%:input%>)<% end %> <% if self.allowany and self.allowlocal then -%>
</label> (<%= self.alias ~= "dest"
and translate("output") or translate("input") %>)
<%- end %>
</span>
</li>
<% elseif self.widget ~= "checkbox" and (self.rmempty or self.optional) then %>
<li value=""<%=ifattr(checked[""], "selected", "selected")%>>
<span class="zonebadge">
<em><%:unspecified%></em>
</span>
</li> </li>
<% end %> <% end %>
<% if self.allowany then %> <% if self.allowany then %>
<li style="padding:0.5em"> <li value="*"<%=ifattr(checked["*"], "selected", "selected")%>>
<input class="cbi-input-radio" data-update="click change"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "_any") .. attr("name", cbid) .. attr("value", "*") .. ifattr(checked["*"], "checked", "checked")%> /> &#160; <span style="background-color:<%=fwm.zone.get_color()%>" class="zonebadge">
<label<%=attr("for", cbid .. "_any")%>></label>
<label<%=attr("for", cbid .. "_any")%> style="background-color:<%=fwm.zone.get_color()%>" class="zonebadge">
<strong><%:Any zone%></strong> <strong><%:Any zone%></strong>
<% if self.allowany and self.allowlocal then %>(<%:forward%>)<% end %> <% if self.allowany and self.allowlocal then %>(<%:forward%>)<% end %>
</label> </span>
</li> </li>
<% end %> <% end %>
<% <%
@ -51,45 +67,42 @@
if zone:name() ~= self.exclude then if zone:name() ~= self.exclude then
selected = selected or (value == zone:name()) selected = selected or (value == zone:name())
%> %>
<li style="padding:0.5em"> <li<%=attr("value", zone:name()) .. ifattr(checked[zone:name()], "selected", "selected")%>>
<input class="cbi-input-radio" data-update="click change"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "." .. zone:name()) .. attr("name", cbid) .. attr("value", zone:name()) .. ifattr(checked[zone:name()], "checked", "checked")%> /> &#160; <span style="background-color:<%=zone:get_color()%>" class="zonebadge">
<label<%=attr("for", cbid .. "." .. zone:name())%>></label>
<label<%=attr("for", cbid .. "." .. zone:name())%> style="background-color:<%=zone:get_color()%>" class="zonebadge">
<strong><%=zone:name()%>:</strong> <strong><%=zone:name()%>:</strong>
<% <%-
local zempty = true local zempty = true
for _, net in ipairs(zone:get_networks()) do for _, net in ipairs(zone:get_networks()) do
net = nwm:get_network(net) net = nwm:get_network(net)
if net then if net then
zempty = false zempty = false
%> -%>
<span class="ifacebadge<% if net:name() == self.network then %> ifacebadge-active<% end %>"><%=net:name()%>: <span class="ifacebadge<% if net:name() == self.network then %> ifacebadge-active<% end %>"><%=net:name()%>:
<% <%-
local nempty = true local nempty = true
for _, iface in ipairs(net:is_bridge() and net:get_interfaces() or { net:get_interface() }) do for _, iface in ipairs(net:is_bridge() and net:get_interfaces() or { net:get_interface() }) do
nempty = false nempty = false
%> %>
<img<%=attr("title", iface:get_i18n())%> style="width:16px; height:16px; vertical-align:middle" src="<%=resource%>/icons/<%=iface:type()%><%=iface:is_up() and "" or "_disabled"%>.png" /> <img<%=attr("title", iface:get_i18n())%> src="<%=resource%>/icons/<%=iface:type()%><%=iface:is_up() and "" or "_disabled"%>.png" />
<% end %> <% end %>
<% if nempty then %><em><%:(empty)%></em><% end %> <% if nempty then %><em><%:(empty)%></em><% end -%>
</span>
<%- end end -%>
<%- if zempty then %><em><%:(empty)%></em><% end -%>
</span> </span>
<% end end %>
<% if zempty then %><em><%:(empty)%></em><% end %>
</label>
</li> </li>
<% end end %> <% end end %>
<% if self.widget ~= "checkbox" and not self.nocreate then %> <% if self.widget ~= "checkbox" and not self.nocreate then %>
<li style="padding:0.5em"> <li value="-">
<input class="cbi-input-radio" data-update="click change" type="radio"<%=attr("id", cbid .. "_new") .. attr("name", cbid) .. attr("value", "-") .. ifattr(not selected, "checked", "checked")%> /> &#160; <span class="zonebadge">
<label<%=attr("for", cbid .. "_new")%>></label> <em><%:create%>:</em>
<div onclick="document.getElementById('<%=cbid%>_new').checked=true" class="zonebadge" style="background-color:<%=fwm.zone.get_color()%>"> <input type="password" style="display:none" />
<em><%:unspecified -or- create:%>&#160;</em> <input class="create-item-input" type="text" />
<input type="text"<%=attr("name", cbid .. ".newzone") .. ifattr(not selected, "value", luci.http.formvalue(cbid .. ".newzone") or self.default)%> onfocus="document.getElementById('<%=cbid%>_new').checked=true" /> </span>
</div>
</li> </li>
<% end %> <% end %>
</ul> </ul>
</span> </div>
<%+cbi/valuefooter%> <%+cbi/valuefooter%>

View file

@ -18,9 +18,11 @@
local checked = { } local checked = { }
if value then if value then
for value in utl.imatch(value) do
for value in utl.imatch(value) do for value in utl.imatch(value) do
checked[value] = true checked[value] = true
end end
end
else else
local n = self.network and net:get_network(self.network) local n = self.network and net:get_network(self.network)
if n then if n then
@ -33,28 +35,32 @@
-%> -%>
<input type="hidden" name="<%=cbeid%>" value="1" /> <input type="hidden" name="<%=cbeid%>" value="1" />
<ul style="margin:0; list-style-type:none">
<div class="cbi-dropdown" display-items="5" placeholder="<%:-- please select -- %>"<%=
attr("name", cbid) ..
ifattr(self.widget == "checkbox", "multiple", "multiple") ..
ifattr(self.widget == "checkbox", "optional", "optional")
%>>
<script type="item-template"><!--
<li value="{{value}}">
<img title="<%:Custom Interface%>: &quot;{{value}}&quot;" src="<%=resource%>/icons/ethernet_disabled.png" />
<span class="hide-open">{{value}}</span>
<span class="hide-close"><%:Custom Interface%>: "{{value}}"</span>
</li>
--></script>
<ul>
<% for _, iface in ipairs(ifaces) do <% for _, iface in ipairs(ifaces) do
local link = iface:adminlink()
if (not self.nobridges or not iface:is_bridge()) and if (not self.nobridges or not iface:is_bridge()) and
(not self.noinactive or iface:is_up()) and (not self.noinactive or iface:is_up()) and
iface:name() ~= self.exclude iface:name() ~= self.exclude
then %> then %>
<li> <li<%=
<input class="cbi-input-<%=self.widget or "radio"%>" data-update="click change"<%= attr("value", iface:name()) ..
attr("type", self.widget or "radio") .. ifattr(checked[iface:name()], "selected", "selected")
attr("id", cbid .. "." .. iface:name()) .. %>>
attr("name", cbid) .. attr("value", iface:name()) .. <img<%=attr("title", iface:get_i18n())%> src="<%=resource%>/icons/<%=iface:type()%><%=iface:is_up() and "" or "_disabled"%>.png" />
ifattr(checked[iface:name()], "checked", "checked") <span class="hide-open"><%=pcdata(iface:name())%></span>
%> /> <span class="hide-close">
<%- if not self.widget or self.widget == "checkbox" or self.widget == "radio" then -%>
<label<%=attr("for", cbid .. "." .. iface:name())%>></label>
<%- end -%>
&#160;
<label<%=attr("for", cbid .. "." .. iface:name())%>>
<% if link then -%><a href="<%=link%>"><% end -%>
<img<%=attr("title", iface:get_i18n())%> style="width:16px; height:16px; vertical-align:middle" src="<%=resource%>/icons/<%=iface:type()%><%=iface:is_up() and "" or "_disabled"%>.png" />
<% if link then -%></a><% end -%>
<%=pcdata(iface:get_i18n())%> <%=pcdata(iface:get_i18n())%>
<% local ns = iface:get_networks(); if #ns > 0 then %>( <% local ns = iface:get_networks(); if #ns > 0 then %>(
<%- local i, n; for i, n in ipairs(ns) do -%> <%- local i, n; for i, n in ipairs(ns) do -%>
@ -62,28 +68,18 @@
<a href="<%=n:adminlink()%>"><%=n:name()%></a> <a href="<%=n:adminlink()%>"><%=n:name()%></a>
<%- end -%> <%- end -%>
)<% end %> )<% end %>
</label> </span>
</li> </li>
<% end end %> <% end end %>
<% if not self.nocreate then %> <% if not self.nocreate then %>
<li> <li value="">
<input class="cbi-input-<%=self.widget or "radio"%>" data-update="click change"<%= <img title="<%:Custom Interface%>" src="<%=resource%>/icons/ethernet_disabled.png" />
attr("type", self.widget or "radio") .. <span><%:Custom Interface%>:</span>
attr("id", cbid .. "_custom") .. <input type="password" style="display:none" />
attr("name", cbid) .. <input class="create-item-input" type="text" />
attr("value", " ")
%> />
<%- if not self.widget or self.widget == "checkbox" or self.widget == "radio" then -%>
<label<%=attr("for", cbid .. "_custom")%>></label>
<%- end -%>
&#160;
<label<%=attr("for", cbid .. "_custom")%>>
<img title="<%:Custom Interface%>" style="width:16px; height:16px; vertical-align:middle" src="<%=resource%>/icons/ethernet_disabled.png" />
<%:Custom Interface%>:
</label>
<input type="text" style="width:50px" onfocus="document.getElementById('<%=cbid%>_custom').checked=true" onblur="var x=document.getElementById('<%=cbid%>_custom'); x.value=this.value; x.checked=true" />
</li> </li>
<% end %> <% end %>
</ul> </ul>
</div>
<%+cbi/valuefooter%> <%+cbi/valuefooter%>

View file

@ -20,66 +20,62 @@
end end
-%> -%>
<ul style="margin:0; list-style-type:none; text-align:left"> <div class="cbi-dropdown" display-items="5" placeholder="<%:-- please select -- %>"<%=
attr("name", cbid) ..
ifattr(self.widget == "checkbox", "multiple", "multiple") ..
ifattr(self.widget == "checkbox", "optional", "optional")
%>>
<script type="item-template"><!--
<li value="{{value}}">
<span class="ifacebadge" style="background:repeating-linear-gradient(45deg,rgba(204,204,204,0.5),rgba(204,204,204,0.5) 5px,rgba(255,255,255,0.5) 5px,rgba(255,255,255,0.5) 10px)">
{{value}}: <em>(<%:create%>)</em>
</span>
</li>
--></script>
<ul>
<% if self.widget ~= "checkbox" then %>
<li value=""<%= ifattr(not value, "selected", "selected") %>>
<em><%:unspecified%></em>
</li>
<% end %>
<% for _, net in ipairs(networks) do <% for _, net in ipairs(networks) do
if (net:name() ~= "loopback") and if (net:name() ~= "loopback") and
(net:name() ~= self.exclude) and (net:name() ~= self.exclude) and
(not self.novirtual or not net:is_virtual()) (not self.novirtual or not net:is_virtual())
then %> then %>
<li style="padding:0.25em 0"> <li<%= attr("value", net:name()) .. ifattr(checked[net:name()], "selected", "selected") %>>
<input class="cbi-input-<%=self.widget or "radio"%>" data-update="click change"<%=
attr("type", self.widget or "radio") ..
attr("id", cbid .. "." .. net:name()) ..
attr("name", cbid) .. attr("value", net:name()) ..
ifattr(checked[net:name()], "checked", "checked")
%> /> &#160;
<label<%=attr("for", cbid .. "." .. net:name())%>>
<span class="ifacebadge"><%=net:name()%>: <span class="ifacebadge"><%=net:name()%>:
<% <%
local empty = true local empty = true
for _, iface in ipairs(net:is_bridge() and net:get_interfaces() or { net:get_interface() }) do for _, iface in ipairs(net:is_bridge() and net:get_interfaces() or { net:get_interface() }) do
if not iface:is_bridge() then if not iface:is_bridge() then
empty = false empty = false
%> -%>
<img<%=attr("title", iface:get_i18n())%> style="width:16px; height:16px; vertical-align:middle" src="<%=resource%>/icons/<%=iface:type()%><%=iface:is_up() and "" or "_disabled"%>.png" /> <img<%=attr("title", iface:get_i18n())%> style="width:16px; height:16px; vertical-align:middle" src="<%=resource%>/icons/<%=iface:type()%><%=iface:is_up() and "" or "_disabled"%>.png" />
<% end end %> <%- end end %>
<% if empty then %><em><%:(no interfaces attached)%></em><% end %> <% if empty then %>
<em class="hide-close"><%:(no interfaces attached)%></em>
<em class="hide-open">-</em>
<% end %>
</span> </span>
</label>
</li> </li>
<% end end %> <% end end %>
<% if not self.nocreate then %> <% if not self.nocreate then %>
<li style="padding:0.25em 0"> <li value="-"<%= ifattr(not value and self.widget ~= "checkbox", "selected", "selected") %>>
<input class="cbi-input-<%=self.widget or "radio"%>" data-update="click change"<%=attr("type", self.widget or "radio") .. attr("id", cbid .. "_new") .. attr("name", cbid) .. attr("value", "-") .. ifattr(not value and self.widget ~= "checkbox", "checked", "checked")%> /> &#160; <em>
<%- if not self.widget or self.widget == "checkbox" or self.widget == "radio" then -%>
<label<%=attr("for", cbid .. "_new")%>></label>
<%- end -%>
<div style="padding:0.5em; display:inline">
<label<%=attr("for", cbid .. "_new")%>><em>
<%- if self.widget == "checkbox" then -%> <%- if self.widget == "checkbox" then -%>
<%:create:%> <%:create:%>
<%- else -%> <%- else -%>
<%:unspecified -or- create:%> <%:unspecified -or- create:%>
<%- end -%>&#160;</em></label> <%- end -%>
</em>
<input style="display:none" type="password" /> <input style="display:none" type="password" />
<input style="width:6em" type="text"<%=attr("name", cbid .. ".newnet")%> onfocus="document.getElementById('<%=cbid%>_new').checked=true" /> <input class="create-item-input" type="text" />
</div>
</li>
<% elseif self.widget ~= "checkbox" and self.unspecified then %>
<li style="padding:0.25em 0">
<input class="cbi-input-<%=self.widget or "radio"%>" data-update="click change"<%=
attr("type", self.widget or "radio") ..
attr("id", cbid .. "_uns") ..
attr("name", cbid) ..
attr("value", "") ..
ifattr(not value or #value == 0, "checked", "checked")
%> /> &#160;
<div style="padding:0.5em; display:inline">
<label<%=attr("for", cbid .. "_uns")%>><em><%:unspecified%></em></label>
</div>
</li> </li>
<% end %> <% end %>
</ul> </ul>
</div>
<%+cbi/valuefooter%> <%+cbi/valuefooter%>

View file

@ -351,7 +351,6 @@ if has_firewall then
fwzone.template = "cbi/firewall_zonelist" fwzone.template = "cbi/firewall_zonelist"
fwzone.network = arg[1] fwzone.network = arg[1]
fwzone.rmempty = false
function fwzone.cfgvalue(self, section) function fwzone.cfgvalue(self, section)
self.iface = section self.iface = section
@ -360,22 +359,16 @@ if has_firewall then
end end
function fwzone.write(self, section, value) function fwzone.write(self, section, value)
local zone = fw:get_zone(value) local zone = fw:get_zone(value) or fw:add_zone(value)
if not zone and value == '-' then
value = m:formvalue(self:cbid(section) .. ".newzone")
if value and #value > 0 then
zone = fw:add_zone(value)
else
fw:del_network(section)
end
end
if zone then if zone then
fw:del_network(section) fw:del_network(section)
zone:add_network(section) zone:add_network(section)
end end
end end
function fwzone.remove(self, section)
fw:del_network(section)
end
end end

View file

@ -390,22 +390,16 @@ network.novirtual = true
function network.write(self, section, value) function network.write(self, section, value)
local i = nw:get_interface(section) local i = nw:get_interface(section)
if i then if i then
if value == '-' then local _, net, old, new = nil, nil, {}, {}
value = m:formvalue(self:cbid(section) .. ".newnet")
if value and #value > 0 then for _, net in ipairs(i:get_networks()) do
local n = nw:add_network(value, {proto="none"}) old[net:name()] = true
if n then n:add_interface(i) end
else
local n = i:get_network()
if n then n:del_interface(i) end
end end
else
local v for net in ut.imatch(value) do
for _, v in ipairs(i:get_networks()) do new[net] = true
v:del_interface(i) if not old[net] then
end local n = nw:get_network(net) or nw:add_network(net, { proto = "none" })
for v in ut.imatch(value) do
local n = nw:get_network(v)
if n then if n then
if not n:is_empty() then if not n:is_empty() then
n:set("type", "bridge") n:set("type", "bridge")
@ -414,6 +408,15 @@ function network.write(self, section, value)
end end
end end
end end
for net, _ in pairs(old) do
if not new[net] then
local n = nw:get_network(net)
if n then
n:del_interface(i)
end
end
end
end end
end end

View file

@ -94,14 +94,9 @@ function newnet.parse(self, section)
local net, zone local net, zone
if has_firewall then if has_firewall then
local zval = fwzone:formvalue(section) local value = fwzone:formvalue(section)
zone = fw:get_zone(zval) if value and #value > 0 then
zone = fw:get_zone(value) or fw:add_zone(value)
if not zone and zval == '-' then
zval = m:formvalue(fwzone:cbid(section) .. ".newzone")
if zval and #zval > 0 then
zone = fw:add_zone(zval)
end
end end
end end