Skip to content

Commit

Permalink
Merge pull request #106 from maxfordham:98-editgrid-datahandler-revie…
Browse files Browse the repository at this point in the history
…w-and-copy-dialogue

98-editgrid-datahandler-review-and-copy-dialogue
  • Loading branch information
jgunstone authored Jan 26, 2023
2 parents 635087a + 7d09f55 commit 8d646d9
Show file tree
Hide file tree
Showing 2 changed files with 106 additions and 75 deletions.
39 changes: 23 additions & 16 deletions src/ipyautoui/custom/buttonbars.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,18 +51,14 @@ def _default_fns_onsave(self):
s = f"fns_onsave - action called @ {datetime.now().strftime('%H:%M:%S')}"
log_fns_onsave = lambda: logging.info(s)
log_fns_onsave.__name__ = "log_fns_onsave"
print_fns_onsave = lambda: print(s)
print_fns_onsave.__name__ = "print_fns_onsave"
return [log_fns_onsave, print_fns_onsave]
return [log_fns_onsave] # , print_fns_onsave

@tr.default("fns_onrevert")
def _default_fn_revert(self):
s = f"log_fns_onrevert - action called @ {datetime.now().strftime('%H:%M:%S')}"
log_fns_onrevert = lambda: logging.info(s)
log_fns_onrevert.__name__ = "log_fns_onrevert"
print_fns_onrevert = lambda: print(s)
print_fns_onrevert.__name__ = "print_fns_onrevert"
return [log_fns_onrevert, print_fns_onrevert]
return [log_fns_onrevert] # , print_fns_onrevert

def fn_save(self):
"""do not edit"""
Expand Down Expand Up @@ -113,7 +109,7 @@ def _add_action(
fns = [fn_add] + fns
else:
fns = fns + [fn_add]
setattr(self, action_name, fns + [fn_add])
setattr(self, action_name, fns)

def fns_onsave_add_action(
self,
Expand Down Expand Up @@ -146,17 +142,22 @@ def fns_onrevert_add_action(
)


# -

if __name__ == "__main__":
actions = SaveActions()
f = lambda: print("test")
f.__name__ = "asdf"
f.__name__ = "f"
f1 = lambda: print("test1")
f1.__name__ = "asdf"

f1.__name__ = "f1"
print("f")
print("-----")
actions.fns_onsave_add_action(f)
actions.fns_onsave_add_action(f1)
actions.fn_save()

print("")
print("f1")
print("-----")
actions.fns_onrevert_add_action(f)
actions.fns_onrevert_add_action(f1)
actions.fn_revert()
Expand Down Expand Up @@ -238,10 +239,18 @@ def _observe_tgl_unsaved_changes(self, onchange):
# -

if __name__ == "__main__":
sb.unsaved_changes = True
f = lambda: print("test")
f.__name__ = "f"
f1 = lambda: print("test1")
f1.__name__ = "f1"
sb.fns_onsave_add_action(f)
sb.fns_onsave_add_action(f1)

# TODO: move into editgrid_buttonbar.py
sb.fns_onrevert_add_action(f)
sb.fns_onrevert_add_action(f1)

if __name__ == "__main__":
sb.unsaved_changes = True

# +
BUTTONBAR_CONFIG = {
Expand Down Expand Up @@ -291,8 +300,7 @@ class CrudButtonBar(w.HBox):
def _observe_active(self, change):
if change["new"] is None:
self.message.value = ""
print(change["new"])
print(self.message.value)
logging.info(f"active CRUD view = {change['new']}")

def __init__(
self,
Expand Down Expand Up @@ -364,7 +372,6 @@ def _onclick(self, button_name):
w.tooltip = BUTTONBAR_CONFIG[button_name]["tooltip"]
w.layout.border = None
self.fn_backward()
print(self.message.value)

def _add(self, onchange):
self._onclick("add")
Expand Down
142 changes: 83 additions & 59 deletions src/ipyautoui/custom/editgrid.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,7 @@ def is_incremental(li):


# TODO: create an AutoUiSchema class to handle schema gen and then extend it here...
# TODO: consider extending by using pandera
# TODO: consider extending by using pandera (schema defs and validation for pandas)
class GridSchema:
"""
NOTE: index below can be either column index or row index. it can be swapped using
Expand Down Expand Up @@ -500,10 +500,8 @@ def is_transposed(self):
else:
cols_check = self.gridschema.property_keys
if set(cols_check) == set(self.column_names):
# print(f"{str(cols_check)} == {str(set(self.column_names))}")
return False
else:
# print(f"{str(cols_check)} != {str(set(self.column_names))}")
return True

def records(self, keys_as_title=False):
Expand Down Expand Up @@ -609,14 +607,35 @@ def _init_data(self, data) -> pd.DataFrame:

return self.map_column_index_to_data(data)

def set_cell_value_if_different(self, column_name, primary_key_value, new_value):
old = self.get_cell_value(column_name, primary_key_value)
if len(old) != 1:
raise ValueError(
f"multiple values return from: self.get_cell_value({column_name}, {primary_key_value})"
)
else:
old = old[0]
if old != new_value:
s = f"(column_name={column_name}, primary_key_value={primary_key_value}) old={old}, new={new_value})"
logging.info(s)
print(s)
self.set_cell_value(column_name, primary_key_value, new_value)
return {
"column_name": column_name,
"primary_key_value": primary_key_value,
"new_value": new_value,
}
else:
pass

def set_item_value(self, index: int, value: dict):
"""
set row (transposed==False) or col (transposed==True) value
"""
if self.transposed:
self.set_col_value(index, value)
return self.set_col_value(index, value)
else:
self.set_row_value(index, value)
return self.set_row_value(index, value)

def set_row_value(self, index: int, value: dict):
"""Set a chosen row using the key and a value given.
Expand All @@ -635,8 +654,11 @@ def set_row_value(self, index: int, value: dict):
pass
else:
raise Exception("Columns of value given do not match with value keys.")
for column, v in value.items():
self.set_cell_value(column, index, v)
changes = [
self.set_cell_value_if_different(column, index, v)
for column, v in value.items()
]
return [c for c in changes if c is not None]

def apply_map_name_title(self, row_data):
return {
Expand All @@ -660,11 +682,14 @@ def set_col_value(self, index: int, value: dict):
value = {self.map_name_index.get(name): v for name, v in value.items()}
if set(value.keys()) != set(self.data.index.to_list()):
raise Exception("Index of datagrid does not match with value keys.")
changes = []
for primary_key_value, v in value.items():
# set_cell_value(self, column_name, primary_key_value, new_value)
if isinstance(primary_key_value, tuple):
primary_key_value = list(primary_key_value)
self.set_cell_value(column_name, primary_key_value, v)
changes.append(
self.set_cell_value_if_different(column_name, primary_key_value, v)
)
return [c for c in changes if c is not None]

def filter_by_column_name(self, column_name: str, li_filter: list):
"""Filter rows to display based on a column name and a list of objects belonging to that column.
Expand Down Expand Up @@ -1171,9 +1196,7 @@ def transposed(self, value: bool):
self.grid.transposed = value

def _update_value_from_grid(self):
# print(self._value) # old
self._value = self.grid.records()
# print(self._value) # new

@value.setter
def value(self, value):
Expand Down Expand Up @@ -1203,21 +1226,22 @@ def __init__(
close_crud_dialogue_on_action: bool = False,
description: str = "",
fn_on_copy: ty.Callable = None, # TODO: don't think this is required... should be handled by an observe?
**kwargs,
):
self.description = w.HTML(description)
self.by_title = by_title
self.fn_on_copy = fn_on_copy
self.by_alias = by_alias
self.datahandler = datahandler
self.grid = AutoGrid(schema, value=value, by_alias=self.by_alias)
self.grid = AutoGrid(schema, value=value, by_alias=self.by_alias, **kwargs)

self._init_form()
if ui_add is None:
self.ui_add = aui.AutoObject(self.row_schema)
self.ui_add = AutoObjectFiltered(self.row_schema, app=self)
else:
self.ui_add = ui_add(self.row_schema, app=self)
if ui_edit is None:
self.ui_edit = aui.AutoObject(self.row_schema)
self.ui_edit = AutoObjectFiltered(self.row_schema, app=self)
else:
self.ui_edit = ui_edit(self.row_schema, app=self)
if ui_delete is None:
Expand Down Expand Up @@ -1247,7 +1271,6 @@ def __init__(
self.stk_crud,
self.grid,
]
# self.setview_default()
self._init_controls()

def _init_row_controls(self):
Expand Down Expand Up @@ -1322,7 +1345,8 @@ def _validate_edit_click(self):
self._check_one_row_selected()

def _save_edit_to_grid(self):
self.grid.set_item_value(self.grid.selected_index, self.ui_edit.value)
changes = self.grid.set_item_value(self.grid.selected_index, self.ui_edit.value)
# TODO: patch changes back to source
if self.close_crud_dialogue_on_action:
self.buttonbar_grid.edit.value = False

Expand Down Expand Up @@ -1453,12 +1477,12 @@ def _delete_selected(self):
self.buttonbar_grid.delete.value = False

def _set_ui_delete_to_selected_row(self):
logging.info(f"delete: {self.grid.selected_dict}")
self.ui_delete.value = self.grid.selected_dict

def _delete(self):
try:
if len(self.grid.selected_indexes) > 0:
print(f"Row Number: {self.grid.selected_indexes}")
if not self.warn_on_delete:
self.buttonbar_grid.delete.value = False
self._delete_selected()
Expand All @@ -1475,48 +1499,6 @@ def _delete(self):
traceback.print_exc()


if __name__ == "__main__":
# Test: EditGrid instance with multi-indexing.
AUTO_GRID_DEFAULT_VALUE = [
{
"string": "important string",
"integer": 1,
"floater": 3.14,
},
]
AUTO_GRID_DEFAULT_VALUE = AUTO_GRID_DEFAULT_VALUE * 4

class DataFrameCols(BaseModel):
string: str = Field("string", column_width=100, section="a")
integer: int = Field(1, column_width=80, section="a")
floater: float = Field(None, column_width=70, aui_sig_fig=3, section="b")

class TestDataFrame(BaseModel):
"""a description of TestDataFrame"""

__root__: ty.List[DataFrameCols] = Field(
default=AUTO_GRID_DEFAULT_VALUE,
format="dataframe",
datagrid_index_name=("section", "title"),
)

description = markdown(
"<b>The Wonderful Edit Grid Application</b><br>Useful for all editing purposes"
" whatever they may be 👍"
)
editgrid = EditGrid(
schema=TestDataFrame,
description=description,
ui_add=None,
ui_edit=None,
warn_on_delete=True,
show_copy_dialogue=False,
close_crud_dialogue_on_action=False,
)
editgrid.observe(lambda c: print("_value changed"), "_value")
display(editgrid)


class AutoObjectFiltered(
aui.AutoObject
): # TODO: Implement into EditGrid class by default... !
Expand Down Expand Up @@ -1568,6 +1550,48 @@ def _save_previous_selections(self, onchange):
self._selections = self.app.grid.selections


if __name__ == "__main__":
# Test: EditGrid instance with multi-indexing.
AUTO_GRID_DEFAULT_VALUE = [
{
"string": "important string",
"integer": 1,
"floater": 3.14,
},
]
AUTO_GRID_DEFAULT_VALUE = AUTO_GRID_DEFAULT_VALUE * 4

class DataFrameCols(BaseModel):
string: str = Field("string", column_width=100, section="a")
integer: int = Field(1, column_width=80, section="a")
floater: float = Field(None, column_width=70, aui_sig_fig=3, section="b")

class TestDataFrame(BaseModel):
"""a description of TestDataFrame"""

__root__: ty.List[DataFrameCols] = Field(
default=AUTO_GRID_DEFAULT_VALUE,
format="dataframe",
datagrid_index_name=("section", "title"),
)

description = markdown(
"<b>The Wonderful Edit Grid Application</b><br>Useful for all editing purposes"
" whatever they may be 👍"
)
editgrid = EditGrid(
schema=TestDataFrame,
description=description,
ui_add=None,
ui_edit=None,
warn_on_delete=True,
show_copy_dialogue=False,
close_crud_dialogue_on_action=False,
)
editgrid.observe(lambda c: print("_value changed"), "_value")
display(editgrid)


if __name__ == "__main__":
# Test: Using AutoObjectFiltered
editgrid = EditGrid(
Expand Down

0 comments on commit 8d646d9

Please sign in to comment.