3
0
Fork 0

feat: add basic Table views

very minimal so far, just laying foundations
This commit is contained in:
Lance Edgar 2025-12-21 16:06:02 -06:00
parent d6a4c5e657
commit 6791abe96f
6 changed files with 212 additions and 0 deletions

View file

@ -0,0 +1,6 @@
``wuttaweb.views.tables``
=========================
.. automodule:: wuttaweb.views.tables
:members:

View file

@ -70,6 +70,7 @@ the narrative docs are pretty scant. That will eventually change.
api/wuttaweb.views.reports api/wuttaweb.views.reports
api/wuttaweb.views.roles api/wuttaweb.views.roles
api/wuttaweb.views.settings api/wuttaweb.views.settings
api/wuttaweb.views.tables
api/wuttaweb.views.upgrades api/wuttaweb.views.upgrades
api/wuttaweb.views.users api/wuttaweb.views.users

View file

@ -32,6 +32,18 @@
</div> </div>
</nav> </nav>
<div class="buttons">
% if request.has_perm("tables.list"):
<wutta-button type="is-primary"
tag="a" href="${url('tables')}"
icon-left="table"
label="Database Tables"
once />
% endif
</div>
<nav class="panel"> <nav class="panel">
<p class="panel-heading">Configuration Files</p> <p class="panel-heading">Configuration Files</p>
<div class="panel-block"> <div class="panel-block">

View file

@ -38,6 +38,7 @@ That will in turn include the following modules:
* :mod:`wuttaweb.views.roles` * :mod:`wuttaweb.views.roles`
* :mod:`wuttaweb.views.users` * :mod:`wuttaweb.views.users`
* :mod:`wuttaweb.views.upgrades` * :mod:`wuttaweb.views.upgrades`
* :mod:`wuttaweb.views.tables`
""" """
@ -55,6 +56,7 @@ def defaults(config, **kwargs): # pylint: disable=missing-function-docstring
config.include(mod("wuttaweb.views.roles")) config.include(mod("wuttaweb.views.roles"))
config.include(mod("wuttaweb.views.users")) config.include(mod("wuttaweb.views.users"))
config.include(mod("wuttaweb.views.upgrades")) config.include(mod("wuttaweb.views.upgrades"))
config.include(mod("wuttaweb.views.tables"))
def includeme(config): # pylint: disable=missing-function-docstring def includeme(config): # pylint: disable=missing-function-docstring

View file

@ -0,0 +1,135 @@
# -*- coding: utf-8; -*-
################################################################################
#
# wuttaweb -- Web App for Wutta Framework
# Copyright © 2024-2025 Lance Edgar
#
# This file is part of Wutta Framework.
#
# Wutta Framework is free software: you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any
# later version.
#
# Wutta Framework is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# Wutta Framework. If not, see <http://www.gnu.org/licenses/>.
#
################################################################################
"""
Table Views
"""
import sqlalchemy as sa
from wuttaweb.views import MasterView
class TableView(MasterView):
"""
Master view showing all tables in the :term:`app database`.
Default route prefix is ``tables``.
Notable URLs provided by this class:
* ``/tables/``
"""
model_name = "table"
model_title = "Database Table"
model_key = "name"
filterable = False
sortable = True
sort_on_backend = False
paginated = True
paginate_on_backend = False
creatable = False
editable = False
deletable = False
labels = {
"name": "Table Name",
}
grid_columns = [
"name",
"schema",
# "row_count",
]
sort_defaults = "name"
form_fields = [
"name",
"schema",
# "row_count",
]
def get_grid_data( # pylint: disable=empty-docstring
self, columns=None, session=None
):
""" """
model = self.app.model
data = []
for table in model.Base.metadata.tables.values():
data.append(
{
"name": table.name,
"schema": table.schema or "",
# "row_count": 42,
}
)
return data
def configure_grid(self, grid): # pylint: disable=empty-docstring
""" """
g = grid
super().configure_grid(g)
# schema
g.set_searchable("schema")
# name
g.set_searchable("name")
g.set_link("name")
def get_instance(self): # pylint: disable=empty-docstring
""" """
if "_cached_instance" not in self.__dict__:
model = self.app.model
name = self.request.matchdict["name"]
table = model.Base.metadata.tables[name]
data = {
"name": table.name,
"schema": table.schema or "",
# "row_count": 42,
}
self.__dict__["_cached_instance"] = data
return self.__dict__["_cached_instance"]
def get_instance_title(self, instance): # pylint: disable=empty-docstring
""" """
return instance["name"]
def defaults(config, **kwargs): # pylint: disable=missing-function-docstring
base = globals()
TableView = kwargs.get( # pylint: disable=invalid-name,redefined-outer-name
"TableView", base["TableView"]
)
TableView.defaults(config)
def includeme(config): # pylint: disable=missing-function-docstring
defaults(config)

View file

@ -0,0 +1,56 @@
# -*- coding: utf-8; -*-
from unittest.mock import patch
from wuttaweb.testing import WebTestCase
from wuttaweb.views import tables as mod
class TestUpgradeView(WebTestCase):
def make_view(self):
return mod.TableView(self.request)
def test_includeme(self):
self.pyramid_config.include("wuttaweb.views.tables")
def test_get_grid_data(self):
view = self.make_view()
data = view.get_grid_data()
self.assertIsInstance(data, list)
self.assertGreater(len(data), 0)
table = data[0]
self.assertIsInstance(table, dict)
self.assertIn("name", table)
self.assertIn("schema", table)
def test_configure_grid(self):
model = self.app.model
view = self.make_view()
# sanity / coverage check
grid = view.make_grid(columns=["name", "schema"])
view.configure_grid(grid)
def test_get_instance(self):
model = self.app.model
view = self.make_view()
with patch.object(self.request, "matchdict", new={"name": "person"}):
table1 = view.get_instance()
self.assertIsInstance(table1, dict)
self.assertIn("name", table1)
self.assertEqual(table1["name"], "person")
self.assertIn("schema", table1)
table2 = view.get_instance()
self.assertIs(table2, table1)
self.assertEqual(table2["name"], "person")
def test_get_instance_title(self):
model = self.app.model
view = self.make_view()
table = {"name": "poser_foo"}
self.assertEqual(view.get_instance_title(table), "poser_foo")