Skip to content

Interactive Data Table

Spera Alfredo Jeshoua edited this page May 14, 2025 · 3 revisions

VM Lab Project Structure Badge

Description

This is a table where for each row you can define some buttons.

It is used for displaying Virtual Machines, Users and Bookmarks in the project.

The interactive_data_table function

Input

  • key (str): The unique key to give to this table's elements.
  • data (list[dict]): The data to display in the table. Each dictionary inside this list should have:
    • the data of the entry
    • buttons_disabled (dict, optional): Used to tell what button (defined in the button_settings) is disabled for this entry in data.
  • refresh_data_callback (Callable, default=None): Highly recommended defining this when pulling data from a database, more below. Enables the "Refresh Data" button if not None. A function to call when the Refresh button in the filters is pressed. It MUST return the same kind of list of dictionaries (like data).
  • column_settings (dict): It defines how should the columns be. Each key inside the dictionary represents the column type, while its value (another dictionary) represents the various settings for that column:
    • column_width (int, default=1): The width of the column.
    • data_name (str): The name of the field in the data input dictionary.
  • button_settings (dict): It defines what buttons should be included for each row. Each key inside the dictionary represents the label of the button, while its value (another dictionary) represents the various settings for that button:
    • callback (Callable): The function to call when the button is pressed. It MUST have a parameter called data_row, where the row that has been clicked is placed.
    • primary (bool, default=False): Whether the button should have the "primary" or "secondary" style.
    • icon (str, default=""): The icon (or emoji) to put before the label on the button.
    • show_only_icon (bool, default=False): Whether to show only the icon (if provided).
    • help (str, default=None): The tooltip shown when the mouse hovers on this button. If left at None, the tooltip is not rendered.
  • popover_settings (dict, default=None): If not None, shows a popover containing all buttons defined in button_settings:
    • text (str, default="Open"): The text to display in the popover.
    • icon (str, default=None): The icon to display in the popover.
  • filters_expanded (bool, default=False): Whether the filters are expanded or not.
  • clear_filters_button (bool, default=True): Whether to display the "Clear Filters" button in the filters' menu.
  • title (str, default=None): The title (in markdown) to display above the table. If left at None, the title is not rendered.
  • action_header_name (str, default="Actions"): The string to show in the header of the buttons' header.

Output

This function does not return an output, but it renders a component.

Raises a ValueError if data_name is not defined in a column_settings entry.

Notes

Usage with a Database

Important

It is recommended to create a refresh_data_callback function to make the page more efficient.

Without this, each time the user changes a filter, the table makes a new unnecessary request to the database.

The refresh_data_callback should have the st.cache_data decorator and should return the list of entry dictionaries.

For example:

@st.cache_data
def get_data_from_db():
    # Get the data from the db
    # ...
    
    # Insert for each entry a "buttons_disabled" dictionary
    # ...

    # Return the list

Set the refresh_data_callback to this function. If you need to pass a parameter to it, send a lambda.

Use popover instead of buttons on the table

Instead of showing multiple buttons on a row, you can show only one button (a popover) that shows all the buttons defined, like a dialog.

image_popover

To do this, pass a valid dictionary for popover_settings.

Hide data in data_row

You can store hidden data inside a list entry to use it later, as long as you don't define it in column_settings.

Usage Example

No parameters

@st.cache_data
def get_data_from_db():
    with get_db() as db_list:
        print("Accessing db...")
        vm_list = VirtualMachine.find_all(db_list)

    result = []
    for vm in vm_list:
        vm_dict = {
            "original_object": vm, # Hidden object from the db ready to use
            "id": vm.id,
            "name": vm.name,
            "buttons_disabled": {
                "Edit": False,
                "Delete": True,
                "Connect": False
            }
        }
        print(vm_dict)
        result.append(vm_dict)

    return result


@st.dialog("Edit")
def edit_callback(data_row):
    st.write(f"**Editing** vm {data_row['name']} with ID {data_row['id']}")

@st.dialog("Delete")
def delete_callback(data_row):
    st.write(f"**Deleting** vm {data_row['name']} with ID {data_row['id']}")

@st.dialog("Connect")
def connect_callback(data_row):
    st.write(f"**Connecting** to vm {data_row['name']} with ID {data_row['id']}")


interactive_data_table(
    data=get_data_from_db(),
    refresh_data_callback=get_data_from_db,
    column_settings={
        "VM ID": {
            "column_width": 1,
            "data_name": "id"
        },
        "Name": {
            "column_width": 2,
            "data_name": "name"
        },
    },
    button_settings={
        "Edit": {
            "primary": False,
            "callback": edit_callback,
            "icon": ":material/edit:",
            "show_only_icon": False,
            "help": "Edit this"
        },
        "Delete": {
            "primary": False,
            "callback": delete_callback,
            "icon": ":material/delete:",
            "show_only_icon": False,
            "help": "Delete this"
        },
        "Connect": {
            "primary": True,
            "callback": connect_callback,
            "icon": ":material/arrow_forward:",
            "show_only_icon": False
        }
    },
)
Image

Pass parameters to the callback function

@st.cache_data
def get_data_from_db(parameter1, parameter2):
    # ...


interactive_data_table(
    data=get_data_from_db("My param1", "My param2"),
    refresh_data_callback=lambda: get_data_from_db("My param1", "My param2"),
    # ...
)

With fixed data

fixed_data = [
    {
        "id": 1,
        "name": John,
        "buttons_disabled": {
            "Edit": False,
            "Delete": True,
            "Connect": False
    },
    # ...
]


interactive_data_table(
    data=fixed_data,
    # ...
)

Clone this wiki locally