diff --git a/luci-app-modem/luasrc/view/modem/tblsection.htm b/luci-app-modem/luasrc/view/modem/tblsection.htm
new file mode 100644
index 0000000..1cba660
--- /dev/null
+++ b/luci-app-modem/luasrc/view/modem/tblsection.htm
@@ -0,0 +1,203 @@
+<%-
+local rowcnt = 0
+
+function rowstyle()
+ rowcnt = rowcnt + 1
+ if rowcnt % 2 == 0 then
+ return " cbi-rowstyle-1"
+ else
+ return " cbi-rowstyle-2"
+ end
+end
+
+function width(o)
+ if o.width then
+ if type(o.width) == 'number' then
+ return ' style="width:%dpx"' % o.width
+ end
+ return ' style="width:%s"' % o.width
+ end
+ return ''
+end
+
+local has_titles = false
+local has_descriptions = false
+
+local anonclass = (not self.anonymous or self.sectiontitle) and "named" or "anonymous"
+local titlename = ifattr(not self.anonymous or self.sectiontitle, "data-title", translate("Name"))
+
+local i, k
+for i, k in pairs(self.children) do
+ if not k.typename then
+ k.typename = k.template and k.template:gsub("^.+/", "") or ""
+ end
+
+ if not has_titles and k.title and #k.title > 0 then
+ has_titles = true
+ end
+
+ if not has_descriptions and k.description and #k.description > 0 then
+ has_descriptions = true
+ end
+end
+
+function render_titles()
+ if not has_titles then
+ return
+ end
+
+ %>
><%
+
+ local i, k
+ for i, k in ipairs(self.children) do
+ if not k.optional then
+ %>
<%
+ end
+ end
+
+ if self.sortable or self.extedit or self.addremove then
+ %>
<%
+ end
+
+ %>
<%
+
+ rowcnt = rowcnt + 1
+end
+
+function render_descriptions()
+ if not has_descriptions then
+ return
+ end
+
+ %>
<%
+
+ local i, k
+ for i, k in ipairs(self.children) do
+ if not k.optional then
+ %>
><%
+
+ write(k.description)
+
+ %>
<%
+ end
+ end
+
+ if self.sortable or self.extedit or self.addremove then
+ %>
<%
+ end
+
+ %>
<%
+
+ rowcnt = rowcnt + 1
+end
+
+-%>
+
+
+
+ <% if self.title and #self.title > 0 then -%>
+
<%=self.title%>
+ <%- end %>
+ <%- if self.sortable then -%>
+
+ <%- end -%>
+
<%=self.description%>
+
+ <%-
+ render_titles()
+ render_descriptions()
+
+ local isempty, section, i, k = true, nil, nil
+ for i, k in ipairs(self:cfgsections()) do
+ isempty = false
+ section = k
+
+ local sectionname = striptags((type(self.sectiontitle) == "function") and self:sectiontitle(section) or k)
+ local sectiontitle = ifattr(sectionname and (not self.anonymous or self.sectiontitle), "data-title", sectionname, true)
+ local colorclass = (self.extedit or self.rowcolors) and rowstyle() or ""
+ local scope = {
+ valueheader = "cbi/cell_valueheader",
+ valuefooter = "cbi/cell_valuefooter"
+ }
+ -%>
+
>
+ <%-
+ local node
+ for k, node in ipairs(self.children) do
+ if not node.optional then
+ node:render(section, scope or {})
+ end
+ end
+ -%>
+
+ <%- if self.sortable or self.extedit or self.addremove then -%>
+
+
+ <%- if self.sortable then -%>
+
+
+ <% end; if self.extedit then -%>
+ onclick="location.href='<%=self.extedit:format(section)%>'"
+ <%- elseif type(self.extedit) == "function" then
+ %> onclick="location.href='<%=self:extedit(section)%>'"
+ <%- end
+ %> alt="<%:Edit%>" title="<%:Edit%>" />
+ <% end; if self.addremove then %>
+
+ <%- end -%>
+
+
+ <%- end -%>
+
+ <%- end -%>
+
+ <%- if isempty then -%>
+
+
<%:This section contains no values yet%>
+
+ <%- end -%>
+
+
+ <% if self.error then %>
+
+
<% for _, c in pairs(self.error) do for _, e in ipairs(c) do -%>
+
<%=pcdata(e):gsub("\n"," ")%>
+ <%- end end %>
+
+ <% end %>
+
+ <%- if self.addremove then -%>
+ <% if self.template_addremove then include(self.template_addremove) else -%>
+
+ <% if self.anonymous then %>
+
+ <% else %>
+ <% if self.invalid_cts then -%>
+
<%:Invalid%>
+ <%- end %>
+
+
+
+
+ <% end %>
+
+ <%- end %>
+ <%- end -%>
+
+
diff --git a/luci-app-modem/luasrc/view/modem/tblsection_command.htm b/luci-app-modem/luasrc/view/modem/tblsection_command.htm
new file mode 100644
index 0000000..92839c8
--- /dev/null
+++ b/luci-app-modem/luasrc/view/modem/tblsection_command.htm
@@ -0,0 +1,208 @@
+<%-
+local rowcnt = 0
+
+function rowstyle()
+ rowcnt = rowcnt + 1
+ if rowcnt % 2 == 0 then
+ return " cbi-rowstyle-1"
+ else
+ return " cbi-rowstyle-2"
+ end
+end
+
+function width(o)
+ if o.width then
+ if type(o.width) == 'number' then
+ return ' style="width:%dpx"' % o.width
+ end
+ return ' style="width:%s"' % o.width
+ end
+ return ''
+end
+
+local has_titles = false
+local has_descriptions = false
+
+local anonclass = (not self.anonymous or self.sectiontitle) and "named" or "anonymous"
+local titlename = ifattr(not self.anonymous or self.sectiontitle, "data-title", translate("Name"))
+
+local i, k
+for i, k in pairs(self.children) do
+ if not k.typename then
+ k.typename = k.template and k.template:gsub("^.+/", "") or ""
+ end
+
+ if not has_titles and k.title and #k.title > 0 then
+ has_titles = true
+ end
+
+ if not has_descriptions and k.description and #k.description > 0 then
+ has_descriptions = true
+ end
+end
+
+function render_titles()
+ if not has_titles then
+ return
+ end
+
+ %>
>
+
<%:Serial Number%>
+ <%
+ local i, k
+ for i, k in ipairs(self.children) do
+ if not k.optional then
+ %>
<%
+ end
+ end
+
+ if self.sortable or self.extedit or self.addremove then
+ %>
<%
+ end
+
+ %>
<%
+
+ rowcnt = rowcnt + 1
+end
+
+function render_descriptions()
+ if not has_descriptions then
+ return
+ end
+
+ %>
<%
+
+ local i, k
+ for i, k in ipairs(self.children) do
+ if not k.optional then
+ %>
><%
+
+ write(k.description)
+
+ %>
<%
+ end
+ end
+
+ if self.sortable or self.extedit or self.addremove then
+ %>
<%
+ end
+
+ %>
<%
+
+ rowcnt = rowcnt + 1
+end
+
+-%>
+
+
+
+ <% if self.title and #self.title > 0 then -%>
+
<%=self.title%>
+ <%- end %>
+ <%- if self.sortable then -%>
+
+ <%- end -%>
+
<%=self.description%>
+
+ <%-
+ render_titles()
+ render_descriptions()
+
+ local num = 1
+ local isempty, section, i, k = true, nil, nil
+ for i, k in ipairs(self:cfgsections()) do
+ isempty = false
+ section = k
+
+ local sectionname = striptags((type(self.sectiontitle) == "function") and self:sectiontitle(section) or k)
+ local sectiontitle = ifattr(sectionname and (not self.anonymous or self.sectiontitle), "data-title", sectionname, true)
+ local colorclass = (self.extedit or self.rowcolors) and rowstyle() or ""
+ local scope = {
+ valueheader = "cbi/cell_valueheader",
+ valuefooter = "cbi/cell_valuefooter"
+ }
+ -%>
+
>
+
+
<%=num%>
+ <% num = num + 1 -%>
+
+ <%-
+ local node
+ for k, node in ipairs(self.children) do
+ if not node.optional then
+ node:render(section, scope or {})
+ end
+ end
+ -%>
+ <%- if self.sortable or self.extedit or self.addremove then -%>
+
+
+ <%- if self.sortable then -%>
+
+
+ <% end; if self.extedit then -%>
+ onclick="location.href='<%=self.extedit:format(section)%>'"
+ <%- elseif type(self.extedit) == "function" then
+ %> onclick="location.href='<%=self:extedit(section)%>'"
+ <%- end
+ %> alt="<%:Edit%>" title="<%:Edit%>" />
+ <% end; if self.addremove then %>
+
+ <%- end -%>
+
+
+ <%- end -%>
+
+ <%- end -%>
+
+ <%- if isempty then -%>
+
+
<%:This section contains no values yet%>
+
+ <%- end -%>
+
+
+ <% if self.error then %>
+
+
<% for _, c in pairs(self.error) do for _, e in ipairs(c) do -%>
+
<%=pcdata(e):gsub("\n"," ")%>
+ <%- end end %>
+
+ <% end %>
+
+ <%- if self.addremove then -%>
+ <% if self.template_addremove then include(self.template_addremove) else -%>
+
+ <% if self.anonymous then %>
+
+ <% else %>
+ <% if self.invalid_cts then -%>
+