fix: default values in subordinate entities based on static_filtering, add: button visibility callbacks in entities' forms
This commit is contained in:
@@ -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(
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user