3
0
Fork 0

Compare commits

...

6 commits

7 changed files with 142 additions and 86 deletions

View file

@ -2,7 +2,7 @@
################################################################################
#
# wuttaweb -- Web App for Wutta Framework
# Copyright © 2024-2025 Lance Edgar
# Copyright © 2024-2026 Lance Edgar
#
# This file is part of Wutta Framework.
#
@ -30,6 +30,12 @@ import logging
import warnings
from collections import namedtuple, OrderedDict
try:
from enum import EnumType
except ImportError: # pragma: no cover
# nb. python < 3.11
from enum import EnumMeta as EnumType
import sqlalchemy as sa
from sqlalchemy import orm
@ -763,7 +769,7 @@ class Grid: # pylint: disable=too-many-instance-attributes,too-many-public-meth
:param key: Name of column.
:param enum: Instance of :class:`python:enum.Enum`.
:param enum: Instance of :class:`python:enum.Enum`, or a dict.
"""
self.enums[key] = enum
self.set_renderer(key, self.render_enum, enum=enum)
@ -2050,7 +2056,7 @@ class Grid: # pylint: disable=too-many-instance-attributes,too-many-public-meth
See also :meth:`set_enum()`.
:param enum: Enum class for the field. This should be an
instance of :class:`~python:enum.Enum`.
instance of :class:`~python:enum.Enum` or else a dict.
To use this feature for your grid::
@ -2061,12 +2067,26 @@ class Grid: # pylint: disable=too-many-instance-attributes,too-many-public-meth
TWO = 2
THREE = 3
grid.set_enum('my_enum_field', MyEnum)
grid.set_enum("my_enum_field", MyEnum)
Or, perhaps more common::
myenum = {
1: "ONE",
2: "TWO",
3: "THREE",
}
grid.set_enum("my_enum_field", myenum)
"""
if enum:
raw_value = obj[key]
if raw_value:
return raw_value.value
if isinstance(enum, EnumType):
if raw_value := obj[key]:
return raw_value.value
if isinstance(enum, dict):
return enum.get(value, value)
return value

View file

@ -7,86 +7,88 @@
</%def>
<%def name="tool_panel_execution()">
<wutta-tool-panel heading="Execution">
% if batch.executed:
<b-notification :closable="false">
<p class="block">
Batch was executed<br />
${app.render_time_ago(batch.executed)}<br />
by ${batch.executed_by}
</p>
</b-notification>
% elif why_not_execute:
<b-notification type="is-warning" :closable="false">
<p class="block">
Batch cannot be executed:
</p>
<p class="block">
${why_not_execute}
</p>
</b-notification>
% else:
% if master.has_perm('execute'):
<b-notification type="is-success" :closable="false">
% if master.executable:
<wutta-tool-panel heading="Execution">
% if batch.executed:
<b-notification :closable="false">
<p class="block">
Batch can be executed
Batch was executed<br />
${app.render_time_ago(batch.executed)}<br />
by ${batch.executed_by}
</p>
<b-button type="is-primary"
@click="executeInit()"
icon-pack="fas"
icon-left="arrow-circle-right">
Execute Batch
</b-button>
<b-modal has-modal-card
:active.sync="executeShowDialog">
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Execute ${model_title}</p>
</header>
## TODO: forcing black text b/c of b-notification
## wrapping button, which has white text
<section class="modal-card-body has-text-black">
<p class="block has-text-weight-bold">
What will happen when this batch is executed?
</p>
<div class="content">
${execution_described|n}
</div>
${h.form(master.get_action_url('execute', batch), ref='executeForm')}
${h.csrf_token(request)}
${h.end_form()}
</section>
<footer class="modal-card-foot">
<b-button @click="executeShowDialog = false">
Cancel
</b-button>
<b-button type="is-primary"
@click="executeSubmit()"
icon-pack="fas"
icon-left="arrow-circle-right"
:disabled="executeSubmitting">
{{ executeSubmitting ? "Working, please wait..." : "Execute Batch" }}
</b-button>
</footer>
</div>
</b-modal>
</b-notification>
% else:
% elif why_not_execute:
<b-notification type="is-warning" :closable="false">
<p class="block">
Batch may be executed,<br />
but you do not have permission.
Batch cannot be executed:
</p>
<p class="block">
${why_not_execute}
</p>
</b-notification>
% else:
% if master.has_perm('execute'):
<b-notification type="is-success" :closable="false">
<p class="block">
Batch can be executed
</p>
<b-button type="is-primary"
@click="executeInit()"
icon-pack="fas"
icon-left="arrow-circle-right">
Execute Batch
</b-button>
<b-modal has-modal-card
:active.sync="executeShowDialog">
<div class="modal-card">
<header class="modal-card-head">
<p class="modal-card-title">Execute ${model_title}</p>
</header>
## TODO: forcing black text b/c of b-notification
## wrapping button, which has white text
<section class="modal-card-body has-text-black">
<p class="block has-text-weight-bold">
What will happen when this batch is executed?
</p>
<div class="content">
${execution_described|n}
</div>
${h.form(master.get_action_url('execute', batch), ref='executeForm')}
${h.csrf_token(request)}
${h.end_form()}
</section>
<footer class="modal-card-foot">
<b-button @click="executeShowDialog = false">
Cancel
</b-button>
<b-button type="is-primary"
@click="executeSubmit()"
icon-pack="fas"
icon-left="arrow-circle-right"
:disabled="executeSubmitting">
{{ executeSubmitting ? "Working, please wait..." : "Execute Batch" }}
</b-button>
</footer>
</div>
</b-modal>
</b-notification>
% else:
<b-notification type="is-warning" :closable="false">
<p class="block">
Batch may be executed,<br />
but you do not have permission.
</p>
</b-notification>
% endif
% endif
% endif
</wutta-tool-panel>
</wutta-tool-panel>
% endif
</%def>
<%def name="modify_vue_vars()">

View file

@ -2,7 +2,7 @@
################################################################################
#
# wuttaweb -- Web App for Wutta Framework
# Copyright © 2024-2025 Lance Edgar
# Copyright © 2024-2026 Lance Edgar
#
# This file is part of Wutta Framework.
#
@ -32,7 +32,7 @@ import markdown
from sqlalchemy import orm
from wuttaweb.views import MasterView
from wuttaweb.forms.schema import UserRef
from wuttaweb.forms.schema import UserRef, WuttaDictEnum
from wuttaweb.forms.widgets import BatchIdWidget
@ -147,6 +147,9 @@ class BatchMasterView(MasterView):
# description
g.set_link("description")
# status_code
g.set_enum("status_code", self.model_class.STATUS)
def render_batch_id( # pylint: disable=empty-docstring,unused-argument
self, batch, key, value
):
@ -191,6 +194,7 @@ class BatchMasterView(MasterView):
if self.creating:
f.remove("status_code")
else:
f.set_node("status_code", WuttaDictEnum(self.request, batch.STATUS))
f.set_readonly("status_code")
# created
@ -441,7 +445,7 @@ class BatchMasterView(MasterView):
g.set_renderer("status_code", self.render_row_status)
# tool button - create row
if not batch.executed and self.has_perm("create_row"):
if self.rows_creatable and not batch.executed and self.has_perm("create_row"):
button = self.make_button(
f"New {self.get_row_model_title()}",
primary=True,

View file

@ -2,7 +2,7 @@
################################################################################
#
# wuttaweb -- Web App for Wutta Framework
# Copyright © 2024-2025 Lance Edgar
# Copyright © 2024-2026 Lance Edgar
#
# This file is part of Wutta Framework.
#
@ -3514,6 +3514,11 @@ class MasterView(View): # pylint: disable=too-many-public-methods
if hasattr(cls, "model_title"):
return cls.model_title
if model_class := cls.get_model_class():
if hasattr(model_class, "__wutta_hint__"):
if model_title := model_class.__wutta_hint__.get("model_title"):
return model_title
return cls.get_model_name()
@classmethod
@ -3532,6 +3537,13 @@ class MasterView(View): # pylint: disable=too-many-public-methods
if hasattr(cls, "model_title_plural"):
return cls.model_title_plural
if model_class := cls.get_model_class():
if hasattr(model_class, "__wutta_hint__"):
if model_title_plural := model_class.__wutta_hint__.get(
"model_title_plural"
):
return model_title_plural
model_title = cls.get_model_title()
return f"{model_title}s"

View file

@ -96,7 +96,9 @@ class PersonView(MasterView): # pylint: disable=abstract-method
f.remove("full_name")
# users
if self.viewing:
if self.creating or self.editing:
f.remove("users")
elif self.viewing:
f.set_grid("users", self.make_users_grid(person))
def make_users_grid(self, person):

View file

@ -1602,15 +1602,30 @@ class TestGrid(WebTestCase):
grid = self.make_grid(columns=["foo", "bar"])
obj = {"status": None}
# null
# true enum, null
value = grid.render_enum(obj, "status", None, enum=enum.UpgradeStatus)
self.assertIsNone(value)
# normal
# true enum, normal value
obj["status"] = enum.UpgradeStatus.SUCCESS
value = grid.render_enum(obj, "status", "SUCCESS", enum=enum.UpgradeStatus)
self.assertEqual(value, "success")
# dict enum
statuses = {
enum.UpgradeStatus.SUCCESS.name: "success",
enum.UpgradeStatus.FAILURE.name: "failure",
}
# dict enum, null
value = grid.render_enum(obj, "status", None, enum=statuses)
self.assertIsNone(value)
# true enum, normal value
obj["status"] = enum.UpgradeStatus.SUCCESS.value
value = grid.render_enum(obj, "status", "SUCCESS", enum=statuses)
self.assertEqual(value, "success")
def test_render_percent(self):
grid = self.make_grid(columns=["foo", "bar"])
obj = MagicMock()

View file

@ -442,6 +442,7 @@ class TestBatchMasterView(WebTestCase):
mod.BatchMasterView,
model_class=MockBatch,
route_prefix="mock_batches",
rows_creatable=True,
create=True,
):
with patch.object(