I can show and hide the columns comanger
This commit is contained in:
@@ -14,7 +14,7 @@ from myfasthtml.controls.CycleStateControl import CycleStateControl
|
||||
from myfasthtml.controls.DataGridColumnsManager import DataGridColumnsManager
|
||||
from myfasthtml.controls.DataGridQuery import DataGridQuery, DG_QUERY_FILTER
|
||||
from myfasthtml.controls.Mouse import Mouse
|
||||
from myfasthtml.controls.Panel import Panel
|
||||
from myfasthtml.controls.Panel import Panel, PanelConf
|
||||
from myfasthtml.controls.datagrid_objects import DataGridColumnState, DataGridRowState, \
|
||||
DatagridSelectionState, DataGridHeaderFooterConf, DatagridEditionState
|
||||
from myfasthtml.controls.helpers import mk
|
||||
@@ -26,6 +26,7 @@ from myfasthtml.core.optimized_ft import OptimizedDiv
|
||||
from myfasthtml.core.utils import make_safe_id
|
||||
from myfasthtml.icons.carbon import row, column, grid
|
||||
from myfasthtml.icons.fluent import checkbox_unchecked16_regular
|
||||
from myfasthtml.icons.fluent_p1 import settings16_regular
|
||||
from myfasthtml.icons.fluent_p2 import checkbox_checked16_regular
|
||||
|
||||
# OPTIMIZATION: Pre-compiled regex to detect HTML special characters
|
||||
@@ -129,6 +130,13 @@ class Commands(BaseCommands):
|
||||
self._owner,
|
||||
self._owner.on_click
|
||||
).htmx(target=f"#tsm_{self._id}")
|
||||
|
||||
def toggle_columns_manager(self):
|
||||
return Command("ToggleColumnsManager",
|
||||
"Toggle Columns Manager",
|
||||
self._owner,
|
||||
self._owner.toggle_columns_manager
|
||||
).htmx(target=None)
|
||||
|
||||
|
||||
class DataGrid(MultipleInstance):
|
||||
@@ -139,7 +147,10 @@ class DataGrid(MultipleInstance):
|
||||
self.commands = Commands(self)
|
||||
self.init_from_dataframe(self._state.ne_df, init_state=False) # state comes from DatagridState
|
||||
|
||||
self._panel = Panel(self, _id="-panel")
|
||||
# add Panel
|
||||
self._panel = Panel(self, conf=PanelConf(right_title="Columns", show_display_right=False), _id="-panel")
|
||||
self._panel.set_side_visible("right", False) # the right Panel always starts closed
|
||||
self.bind_command("ToggleColumnsManager", self._panel.commands.toggle_side("right"))
|
||||
|
||||
# add DataGridQuery
|
||||
self._datagrid_filter = DataGridQuery(self)
|
||||
@@ -362,6 +373,10 @@ class DataGrid(MultipleInstance):
|
||||
self._state.save()
|
||||
return self.render_partial()
|
||||
|
||||
def toggle_columns_manager(self):
|
||||
logger.debug(f"toggle_columns_manager")
|
||||
self._panel.set_right(self._columns_manager)
|
||||
|
||||
def mk_headers(self):
|
||||
resize_cmd = self.commands.set_column_width()
|
||||
move_cmd = self.commands.move_column()
|
||||
@@ -649,7 +664,7 @@ class DataGrid(MultipleInstance):
|
||||
Div(self._datagrid_filter,
|
||||
Div(
|
||||
self._selection_mode_selector,
|
||||
self._columns_manager,
|
||||
mk.icon(settings16_regular, command=self.commands.toggle_columns_manager(), tooltip="Show sidebar"),
|
||||
cls="flex"),
|
||||
cls="flex items-center justify-between mb-2"),
|
||||
self._panel.set_main(self.mk_table()),
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
from fasthtml.components import *
|
||||
|
||||
from myfasthtml.controls.Dropdown import Dropdown
|
||||
from myfasthtml.controls.Search import Search
|
||||
from myfasthtml.controls.datagrid_objects import DataGridColumnState
|
||||
from myfasthtml.controls.helpers import mk
|
||||
from myfasthtml.icons.fluent_p1 import settings16_regular
|
||||
from myfasthtml.core.instances import MultipleInstance
|
||||
|
||||
|
||||
class DataGridColumnsManager(Dropdown):
|
||||
class DataGridColumnsManager(MultipleInstance):
|
||||
def __init__(self, parent, _id=None):
|
||||
super().__init__(parent, _id=_id, align="right")
|
||||
self.button = mk.icon(settings16_regular)
|
||||
self.content = self.create_content()
|
||||
super().__init__(parent, _id=_id)
|
||||
|
||||
@property
|
||||
def columns(self):
|
||||
return self._parent._state.columns
|
||||
|
||||
def mk_column(self, col_def: DataGridColumnState):
|
||||
return Div(
|
||||
@@ -20,14 +20,14 @@ class DataGridColumnsManager(Dropdown):
|
||||
cls="flex mb-1",
|
||||
)
|
||||
|
||||
def create_content(self):
|
||||
def render(self):
|
||||
return Search(self,
|
||||
items_names="Columns",
|
||||
items=self.columns,
|
||||
get_attr=lambda x: x.col_id,
|
||||
template=self.mk_column
|
||||
template=self.mk_column,
|
||||
max_height=None
|
||||
)
|
||||
|
||||
@property
|
||||
def columns(self):
|
||||
return self._parent._state.columns
|
||||
def __ft__(self):
|
||||
return self.render()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from dataclasses import dataclass
|
||||
from typing import Literal
|
||||
from typing import Literal, Optional
|
||||
|
||||
from fasthtml.components import Div
|
||||
from fasthtml.xtend import Script
|
||||
@@ -42,6 +42,12 @@ class PanelIds:
|
||||
class PanelConf:
|
||||
left: bool = False
|
||||
right: bool = True
|
||||
left_title: str = "Left"
|
||||
right_title: str = "Right"
|
||||
show_left_title: bool = True
|
||||
show_right_title: bool = True
|
||||
show_display_left: bool = True
|
||||
show_display_right: bool = True
|
||||
|
||||
|
||||
class PanelState(DbObject):
|
||||
@@ -55,12 +61,19 @@ class PanelState(DbObject):
|
||||
|
||||
|
||||
class Commands(BaseCommands):
|
||||
def toggle_side(self, side: Literal["left", "right"], visible: bool = None):
|
||||
def set_side_visible(self, side: Literal["left", "right"], visible: bool = None):
|
||||
return Command("TogglePanelSide",
|
||||
f"Toggle {side} side panel",
|
||||
self._owner,
|
||||
self._owner.set_side_visible,
|
||||
args=[side, visible]).htmx(target=f"#{self._owner.get_ids().panel(side)}")
|
||||
|
||||
def toggle_side(self, side: Literal["left", "right"]):
|
||||
return Command("TogglePanelSide",
|
||||
f"Toggle {side} side panel",
|
||||
self._owner,
|
||||
self._owner.toggle_side,
|
||||
args=[side, visible]).htmx(target=f"#{self._owner.get_ids().panel(side)}")
|
||||
args=[side]).htmx(target=f"#{self._owner.get_ids().panel(side)}")
|
||||
|
||||
def update_side_width(self, side: Literal["left", "right"]):
|
||||
"""
|
||||
@@ -89,7 +102,7 @@ class Panel(MultipleInstance):
|
||||
the panel with appropriate HTML elements and JavaScript for interactivity.
|
||||
"""
|
||||
|
||||
def __init__(self, parent, conf=None, _id=None):
|
||||
def __init__(self, parent, conf: Optional[PanelConf] = None, _id=None):
|
||||
super().__init__(parent, _id=_id)
|
||||
self.conf = conf or PanelConf()
|
||||
self.commands = Commands(self)
|
||||
@@ -110,7 +123,7 @@ class Panel(MultipleInstance):
|
||||
|
||||
return self._mk_panel(side)
|
||||
|
||||
def toggle_side(self, side, visible):
|
||||
def set_side_visible(self, side, visible):
|
||||
if side == "left":
|
||||
self._state.left_visible = visible
|
||||
else:
|
||||
@@ -118,6 +131,10 @@ class Panel(MultipleInstance):
|
||||
|
||||
return self._mk_panel(side), self._mk_show_icon(side)
|
||||
|
||||
def toggle_side(self, side):
|
||||
current_visible = self._state.left_visible if side == "left" else self._state.right_visible
|
||||
return self.set_side_visible(side, not current_visible)
|
||||
|
||||
def set_main(self, main):
|
||||
self._main = main
|
||||
return self
|
||||
@@ -134,45 +151,75 @@ class Panel(MultipleInstance):
|
||||
enabled = self.conf.left if side == "left" else self.conf.right
|
||||
if not enabled:
|
||||
return None
|
||||
|
||||
|
||||
visible = self._state.left_visible if side == "left" else self._state.right_visible
|
||||
content = self._right if side == "right" else self._left
|
||||
|
||||
show_title = self.conf.show_left_title if side == "left" else self.conf.show_right_title
|
||||
title = self.conf.left_title if side == "left" else self.conf.right_title
|
||||
|
||||
resizer = Div(
|
||||
cls=f"mf-resizer mf-resizer-{side}",
|
||||
data_command_id=self.commands.update_side_width(side).id,
|
||||
data_side=side
|
||||
)
|
||||
|
||||
|
||||
hide_icon = mk.icon(
|
||||
subtract20_regular,
|
||||
size=20,
|
||||
command=self.commands.toggle_side(side, False),
|
||||
command=self.commands.set_side_visible(side, False),
|
||||
cls="mf-panel-hide-icon"
|
||||
)
|
||||
|
||||
|
||||
panel_cls = f"mf-panel-{side}"
|
||||
if not visible:
|
||||
panel_cls += " mf-hidden"
|
||||
|
||||
if show_title:
|
||||
panel_cls += " mf-panel-with-title"
|
||||
|
||||
# Left panel: content then resizer (resizer on the right)
|
||||
# Right panel: resizer then content (resizer on the left)
|
||||
if side == "left":
|
||||
return Div(
|
||||
if show_title:
|
||||
header = Div(
|
||||
Div(title),
|
||||
hide_icon,
|
||||
Div(content, id=self._ids.content(side)),
|
||||
resizer,
|
||||
cls=panel_cls,
|
||||
id=self._ids.panel(side)
|
||||
cls="mf-panel-header"
|
||||
)
|
||||
body = Div(
|
||||
header,
|
||||
Div(content, id=self._ids.content(side), cls="mf-panel-content"),
|
||||
cls="mf-panel-body"
|
||||
)
|
||||
if side == "left":
|
||||
return Div(
|
||||
body,
|
||||
resizer,
|
||||
cls=panel_cls,
|
||||
id=self._ids.panel(side)
|
||||
)
|
||||
else:
|
||||
return Div(
|
||||
resizer,
|
||||
body,
|
||||
cls=panel_cls,
|
||||
id=self._ids.panel(side)
|
||||
)
|
||||
else:
|
||||
return Div(
|
||||
resizer,
|
||||
hide_icon,
|
||||
Div(content, id=self._ids.content(side)),
|
||||
cls=panel_cls,
|
||||
id=self._ids.panel(side)
|
||||
)
|
||||
if side == "left":
|
||||
return Div(
|
||||
hide_icon,
|
||||
Div(content, id=self._ids.content(side)),
|
||||
resizer,
|
||||
cls=panel_cls,
|
||||
id=self._ids.panel(side)
|
||||
)
|
||||
else:
|
||||
return Div(
|
||||
resizer,
|
||||
hide_icon,
|
||||
Div(content, id=self._ids.content(side)),
|
||||
cls=panel_cls,
|
||||
id=self._ids.panel(side)
|
||||
)
|
||||
|
||||
def _mk_main(self):
|
||||
return Div(
|
||||
@@ -195,13 +242,17 @@ class Panel(MultipleInstance):
|
||||
enabled = self.conf.left if side == "left" else self.conf.right
|
||||
if not enabled:
|
||||
return None
|
||||
|
||||
|
||||
show_display = self.conf.show_display_left if side == "left" else self.conf.show_display_right
|
||||
if not show_display:
|
||||
return None
|
||||
|
||||
is_visible = self._state.left_visible if side == "left" else self._state.right_visible
|
||||
icon_cls = "hidden" if is_visible else f"mf-panel-show-icon mf-panel-show-icon-{side}"
|
||||
|
||||
|
||||
return mk.icon(
|
||||
more_horizontal20_regular,
|
||||
command=self.commands.toggle_side(side, True),
|
||||
command=self.commands.set_side_visible(side, True),
|
||||
cls=icon_cls,
|
||||
id=f"{self._id}_show_{side}"
|
||||
)
|
||||
|
||||
@@ -45,7 +45,8 @@ class Search(MultipleInstance):
|
||||
items_names=None, # what is the name of the items to filter
|
||||
items=None, # first set of items to filter
|
||||
get_attr: Callable[[Any], str] = None, # items is a list of objects: how to get the str to filter
|
||||
template: Callable[[Any], Any] = None): # once filtered, what to render ?
|
||||
template: Callable[[Any], Any] = None, # once filtered, what to render ?
|
||||
max_height: int = 400):
|
||||
"""
|
||||
Represents a component for managing and filtering a list of items based on specific criteria.
|
||||
|
||||
@@ -66,6 +67,7 @@ class Search(MultipleInstance):
|
||||
self.get_attr = get_attr or (lambda x: x)
|
||||
self.template = template or (lambda x: Div(self.get_attr(x)))
|
||||
self.commands = Commands(self)
|
||||
self.max_height = max_height
|
||||
|
||||
def set_items(self, items):
|
||||
self.items = items
|
||||
@@ -106,6 +108,7 @@ class Search(MultipleInstance):
|
||||
*self._mk_search_results(),
|
||||
id=f"{self._id}-results",
|
||||
cls="mf-search-results",
|
||||
style="max-height: 400px;" if self.max_height else None
|
||||
),
|
||||
id=f"{self._id}",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user