fix: default values in subordinate entities based on static_filtering, add: button visibility callbacks in entities' forms

This commit is contained in:
Alexander Kalinovsky
2025-01-22 20:04:32 +01:00
parent 9dd0708a5b
commit b40e588379
7 changed files with 129 additions and 77 deletions

View File

@@ -54,6 +54,9 @@ async def time_picker(
):
keyboard_builder = InlineKeyboardBuilder()
if not current_value:
current_value = time(0, 0)
for i in range(12):
keyboard_builder.row(
InlineKeyboardButton(

View File

@@ -167,6 +167,36 @@ async def process_field_edit_callback(message: Message | CallbackQuery, **kwargs
entity_data = state_data.get("entity_data", {})
if callback_data.context == CommandContext.ENTITY_CREATE:
stack = state_data.get("navigation_stack", [])
prev_callback_data = ContextData.unpack(stack[-1]) if stack else None
if (
prev_callback_data
and prev_callback_data.command == CallbackCommand.ENTITY_LIST
and prev_callback_data.entity_name == entity_descriptor.name
):
prev_form_name = (
prev_callback_data.form_params.split("&")[0]
if prev_callback_data.form_params
else "default"
)
prev_form_params = (
prev_callback_data.form_params.split("&")[1:]
if prev_callback_data.form_params
else []
)
prev_form_list = entity_descriptor.lists.get(
prev_form_name or "default", entity_descriptor.default_list
)
for filt in prev_form_list.static_filters:
if filt.value_type == "const":
entity_data[filt.field_name] = filt.value
elif len(prev_form_params) > filt.param_index:
entity_data[filt.field_name] = prev_form_params[
filt.param_index
]
if (
callback_data.context
in [CommandContext.ENTITY_CREATE, CommandContext.ENTITY_EDIT]

View File

@@ -84,11 +84,15 @@ async def entity_item(
callback_data.form_params or "default", entity_descriptor.default_form
)
if can_edit:
for edit_buttons_row in form.form_buttons:
btn_row = []
for button in edit_buttons_row:
if isinstance(button, FieldEditButton):
if button.visibility and not button.visibility(entity_item):
continue
if isinstance(button, FieldEditButton) and can_edit:
field_name = button.field_name
btn_caption = button.caption
if field_name in entity_descriptor.fields_descriptors:
@@ -114,7 +118,14 @@ async def entity_item(
}"
else:
btn_text = (
f"✏️ {get_callable_str(field_descriptor.caption, field_descriptor, entity_item, field_value)}"
f"✏️ {
get_callable_str(
field_descriptor.caption,
field_descriptor,
entity_item,
field_value,
)
}"
if field_descriptor.caption
else f"✏️ {field_name}"
)
@@ -132,6 +143,7 @@ async def entity_item(
)
elif isinstance(button, CommandButton):
btn_caption = button.caption
if btn_caption:
btn_text = get_callable_str(
@@ -139,18 +151,22 @@ async def entity_item(
)
else:
btn_text = button.command
btn_row.append(
InlineKeyboardButton(
text=btn_text,
callback_data=(
button.context_data.pack()
if button.context_data
else ContextData(
if isinstance(button.context_data, ContextData):
btn_cdata = button.context_data
elif callable(button.context_data):
btn_cdata = button.context_data(callback_data, entity_item)
else:
btn_cdata = ContextData(
command=CallbackCommand.USER_COMMAND,
user_command=button.command,
data=str(entity_item.id),
).pack()
),
)
btn_row.append(
InlineKeyboardButton(
text=btn_text,
callback_data=btn_cdata.pack(),
)
)

View File

@@ -45,6 +45,9 @@ async def entities_menu(
entity_metadata = app.entity_metadata
for entity in entity_metadata.entity_descriptors.values():
if entity.show_in_entities_menu:
if entity.full_name_plural.__class__ == EntityCaptionCallable:
caption = entity.full_name_plural(entity) or entity.name
elif entity.full_name_plural.__class__ == LazyProxy:

View File

@@ -258,7 +258,7 @@ class BotEntity[CreateSchemaType: BaseModel, UpdateSchemaType: BaseModel](
condition = column(sfilt.field_name).isnot(None)
else:
condition = None
if condition:
if condition is not None:
select_statement = select_statement.where(condition)
return select_statement

View File

@@ -24,6 +24,7 @@ EntityFieldCaptionCallable = Callable[["EntityFieldDescriptor", Any, Any], str]
@dataclass
class FieldEditButton:
field_name: str
visibility: Callable[[Any], bool] | None = None
caption: str | LazyProxy | EntityFieldCaptionCallable | None = None
@@ -31,7 +32,8 @@ class FieldEditButton:
class CommandButton:
command: str
caption: str | LazyProxy | EntityItemCaptionCallable | None = None
context_data: ContextData | None = None
visibility: Callable[[Any], bool] | None = None
context_data: ContextData | Callable[[ContextData, Any], ContextData] | None = None
@dataclass
@@ -64,7 +66,7 @@ class EntityList:
item_form: str | None = None
pagination: bool = True
static_filters: list[Filter] | Any = None
filtering: bool = True
filtering: bool = False
filtering_fields: list[str] = None
order_by: str | Any | None = None

View File

@@ -57,12 +57,10 @@ async def deserialize[T](session: AsyncSession, type_: type[T], value: str = Non
elif type_ is datetime:
if is_optional and not value:
return None
if value[-3] == ":":
return datetime.strptime(value, "%Y-%m-%d %H:%M:%S")
elif value[-3] == "-":
if value[-3] == "-":
return datetime.strptime(value, "%Y-%m-%d %H-%M")
else:
raise ValueError("Invalid datetime format")
return datetime.fromisoformat(value)
elif type_ is bool:
return value == "True"
elif type_ is Decimal: