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()
|
keyboard_builder = InlineKeyboardBuilder()
|
||||||
|
|
||||||
|
if not current_value:
|
||||||
|
current_value = time(0, 0)
|
||||||
|
|
||||||
for i in range(12):
|
for i in range(12):
|
||||||
keyboard_builder.row(
|
keyboard_builder.row(
|
||||||
InlineKeyboardButton(
|
InlineKeyboardButton(
|
||||||
|
|||||||
@@ -167,6 +167,36 @@ async def process_field_edit_callback(message: Message | CallbackQuery, **kwargs
|
|||||||
|
|
||||||
entity_data = state_data.get("entity_data", {})
|
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 (
|
if (
|
||||||
callback_data.context
|
callback_data.context
|
||||||
in [CommandContext.ENTITY_CREATE, CommandContext.ENTITY_EDIT]
|
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
|
callback_data.form_params or "default", entity_descriptor.default_form
|
||||||
)
|
)
|
||||||
|
|
||||||
if can_edit:
|
|
||||||
for edit_buttons_row in form.form_buttons:
|
for edit_buttons_row in form.form_buttons:
|
||||||
btn_row = []
|
btn_row = []
|
||||||
for button in edit_buttons_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
|
field_name = button.field_name
|
||||||
btn_caption = button.caption
|
btn_caption = button.caption
|
||||||
if field_name in entity_descriptor.fields_descriptors:
|
if field_name in entity_descriptor.fields_descriptors:
|
||||||
@@ -114,7 +118,14 @@ async def entity_item(
|
|||||||
}"
|
}"
|
||||||
else:
|
else:
|
||||||
btn_text = (
|
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
|
if field_descriptor.caption
|
||||||
else f"✏️ {field_name}"
|
else f"✏️ {field_name}"
|
||||||
)
|
)
|
||||||
@@ -132,6 +143,7 @@ async def entity_item(
|
|||||||
)
|
)
|
||||||
|
|
||||||
elif isinstance(button, CommandButton):
|
elif isinstance(button, CommandButton):
|
||||||
|
|
||||||
btn_caption = button.caption
|
btn_caption = button.caption
|
||||||
if btn_caption:
|
if btn_caption:
|
||||||
btn_text = get_callable_str(
|
btn_text = get_callable_str(
|
||||||
@@ -139,18 +151,22 @@ async def entity_item(
|
|||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
btn_text = button.command
|
btn_text = button.command
|
||||||
btn_row.append(
|
|
||||||
InlineKeyboardButton(
|
if isinstance(button.context_data, ContextData):
|
||||||
text=btn_text,
|
btn_cdata = button.context_data
|
||||||
callback_data=(
|
elif callable(button.context_data):
|
||||||
button.context_data.pack()
|
btn_cdata = button.context_data(callback_data, entity_item)
|
||||||
if button.context_data
|
else:
|
||||||
else ContextData(
|
btn_cdata = ContextData(
|
||||||
command=CallbackCommand.USER_COMMAND,
|
command=CallbackCommand.USER_COMMAND,
|
||||||
user_command=button.command,
|
user_command=button.command,
|
||||||
data=str(entity_item.id),
|
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
|
entity_metadata = app.entity_metadata
|
||||||
|
|
||||||
for entity in entity_metadata.entity_descriptors.values():
|
for entity in entity_metadata.entity_descriptors.values():
|
||||||
|
|
||||||
|
if entity.show_in_entities_menu:
|
||||||
|
|
||||||
if entity.full_name_plural.__class__ == EntityCaptionCallable:
|
if entity.full_name_plural.__class__ == EntityCaptionCallable:
|
||||||
caption = entity.full_name_plural(entity) or entity.name
|
caption = entity.full_name_plural(entity) or entity.name
|
||||||
elif entity.full_name_plural.__class__ == LazyProxy:
|
elif entity.full_name_plural.__class__ == LazyProxy:
|
||||||
|
|||||||
@@ -258,7 +258,7 @@ class BotEntity[CreateSchemaType: BaseModel, UpdateSchemaType: BaseModel](
|
|||||||
condition = column(sfilt.field_name).isnot(None)
|
condition = column(sfilt.field_name).isnot(None)
|
||||||
else:
|
else:
|
||||||
condition = None
|
condition = None
|
||||||
if condition:
|
if condition is not None:
|
||||||
select_statement = select_statement.where(condition)
|
select_statement = select_statement.where(condition)
|
||||||
return select_statement
|
return select_statement
|
||||||
|
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ EntityFieldCaptionCallable = Callable[["EntityFieldDescriptor", Any, Any], str]
|
|||||||
@dataclass
|
@dataclass
|
||||||
class FieldEditButton:
|
class FieldEditButton:
|
||||||
field_name: str
|
field_name: str
|
||||||
|
visibility: Callable[[Any], bool] | None = None
|
||||||
caption: str | LazyProxy | EntityFieldCaptionCallable | None = None
|
caption: str | LazyProxy | EntityFieldCaptionCallable | None = None
|
||||||
|
|
||||||
|
|
||||||
@@ -31,7 +32,8 @@ class FieldEditButton:
|
|||||||
class CommandButton:
|
class CommandButton:
|
||||||
command: str
|
command: str
|
||||||
caption: str | LazyProxy | EntityItemCaptionCallable | None = None
|
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
|
@dataclass
|
||||||
@@ -64,7 +66,7 @@ class EntityList:
|
|||||||
item_form: str | None = None
|
item_form: str | None = None
|
||||||
pagination: bool = True
|
pagination: bool = True
|
||||||
static_filters: list[Filter] | Any = None
|
static_filters: list[Filter] | Any = None
|
||||||
filtering: bool = True
|
filtering: bool = False
|
||||||
filtering_fields: list[str] = None
|
filtering_fields: list[str] = None
|
||||||
order_by: str | Any | None = 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:
|
elif type_ is datetime:
|
||||||
if is_optional and not value:
|
if is_optional and not value:
|
||||||
return None
|
return None
|
||||||
if value[-3] == ":":
|
if value[-3] == "-":
|
||||||
return datetime.strptime(value, "%Y-%m-%d %H:%M:%S")
|
|
||||||
elif value[-3] == "-":
|
|
||||||
return datetime.strptime(value, "%Y-%m-%d %H-%M")
|
return datetime.strptime(value, "%Y-%m-%d %H-%M")
|
||||||
else:
|
else:
|
||||||
raise ValueError("Invalid datetime format")
|
return datetime.fromisoformat(value)
|
||||||
elif type_ is bool:
|
elif type_ is bool:
|
||||||
return value == "True"
|
return value == "True"
|
||||||
elif type_ is Decimal:
|
elif type_ is Decimal:
|
||||||
|
|||||||
Reference in New Issue
Block a user