diff --git a/app.py b/app.py index dec94b0..8f907a3 100644 --- a/app.py +++ b/app.py @@ -52,7 +52,7 @@ # callbacks. external_scripts=[ "https://code.jquery.com/jquery-2.2.4.min.js", - "https://code.jquery.com/ui/1.12.1/jquery-ui.min.js", + "https://code.jquery.com/ui/1.11.4/jquery-ui.min.js", ], # We can use bootstrap CSS. # https://bit.ly/3tMqY0W for details. @@ -590,25 +590,40 @@ def update_hidden_strains(_, deleted_strain, checkbox_ids, checkbox_vals, @app.callback( - Output("select-lineages-modal", "is_open"), Output("select-lineages-modal-body", "children"), + Input("get-data-args", "data"), + State("last-data-mtime", "data"), + prevent_initial_call=True +) +def update_select_lineages_modal_body(get_data_args, last_data_mtime): + """Populate select lineages modal body. + + This is triggered behind the scenes without opening the modal, and + whenever the data is updated. + + :param get_data_args: Args for ``get_data`` + :type get_data_args: dict + :param last_data_mtime: Last mtime across all data files + :type last_data_mtime: float + :return: Content representing the select lineages modal body + :rtype: list[dbc.FormGroup] + """ + data = read_data(get_data_args, last_data_mtime) + return toolbar_generator.get_select_lineages_modal_body(data) + + +@app.callback( + Output("select-lineages-modal", "is_open"), Output("select-lineages-modal-loading", "children"), Input("open-select-lineages-modal-btn", "n_clicks"), Input("select-lineages-ok-btn", "n_clicks"), Input("select-lineages-cancel-btn", "n_clicks"), Input("deleted-strain", "data"), - State("get-data-args", "data"), - State("last-data-mtime", "data"), prevent_initial_call=True ) -def toggle_select_lineages_modal(_, __, ___, ____, get_data_args, - last_data_mtime): +def toggle_select_lineages_modal(_, __, ___, ____): """Open or close select lineages modal. - Not only is this function in charge of opening or closing the - select lineages modal, it is also in charge of dynamically - populating the select lineages modal body when the modal is opened. - This is a little slow to open, so we return ``select-lineages-modal-loading`` to add a spinner. @@ -616,28 +631,18 @@ def toggle_select_lineages_modal(_, __, ___, ____, get_data_args, :param __: OK button in select lineages modal was clicked :param ___: Cancel button in select lineages modal was clicked :param ____: OK button in confirm strain deletion modal was clicked - :param get_data_args: Args for ``get_data`` - :type get_data_args: dict - :param last_data_mtime: Last mtime across all data files - :type last_data_mtime: float :return: Boolean representing whether the select lineages modal is - open or closed, content representing the select lineages - modal body, and ``select-lineages-modal-loading`` children. - :rtype: (bool, list[dbc.FormGroup]) + open or closed, and ``select-lineages-modal-loading`` children. + :rtype: (bool, bool) """ - # Current ``get_data`` return val - data = read_data(get_data_args, last_data_mtime) - ctx = dash.callback_context triggered_prop_id = ctx.triggered[0]["prop_id"] # We only open the modal when the select lineages modal btn in the # toolbar is clicked. if triggered_prop_id == "open-select-lineages-modal-btn.n_clicks": - modal_body = toolbar_generator.get_select_lineages_modal_body(data) - return True, modal_body, None + return True, None else: - # No need to populate modal body if the modal is closed - return False, None, None + return False, None @app.callback( @@ -1410,7 +1415,8 @@ def update_data(get_data_args, last_data_mtime): function_name="makeSelectLineagesModalCheckboxesDraggable" ), Output("make-select-lineages-modal-checkboxes-draggable", "data"), - Input({"type": "select-lineages-modal-checklist", "index": ALL}, "id"), + Input("select-lineages-modal", "is_open"), + State({"type": "select-lineages-modal-checklist", "index": ALL}, "id"), prevent_initial_call=True ) app.clientside_callback( diff --git a/assets/script.js b/assets/script.js index 8ff96a0..64f2ec5 100644 --- a/assets/script.js +++ b/assets/script.js @@ -3,12 +3,13 @@ window.dash_clientside = Object.assign({}, window.dash_clientside, { /** * Make the checkboxes in the select lineage modal draggable within their * respective form groups, using the JQuery UI sortable plugin. + * @param _ Select lineages modal was opened. * @param {Array} idArray Dash pattern matching id values for * checkboxes in select lineages modal. * @return {Boolean} ``true`` if we successfully made the checkboxes * draggable. */ - makeSelectLineagesModalCheckboxesDraggable: (idArray) => { + makeSelectLineagesModalCheckboxesDraggable: (_, idArray) => { // This function responds to all changes in the select lineages modal // body. But the checkboxes disappear when the modal is closed, so we // should do nothing when that happens. diff --git a/generators/toolbar_generator.py b/generators/toolbar_generator.py index 2fbecbf..1ecb3f2 100644 --- a/generators/toolbar_generator.py +++ b/generators/toolbar_generator.py @@ -66,7 +66,7 @@ def get_toolbar_row(data): className="my-auto pl-xl-5", width=2 ), - get_select_lineages_modal(), + get_select_lineages_modal(data), get_confirm_strain_del_modal(), get_jump_to_modal() ], @@ -87,11 +87,13 @@ def get_select_lineages_toolbar_btn(): className="mr-2") -def get_select_lineages_modal(): +def get_select_lineages_modal(data): """Returns select lineages modal. - This modal is initially closed, and the body is empty. + This modal is initially closed. + :param data: ``get_data`` return value + :type data: dict :return: Initially closed Dash Bootstrap Components modal for selecting lineages. :rtype: dbc.Modal @@ -99,7 +101,7 @@ def get_select_lineages_modal(): return dbc.Modal([ dbc.ModalHeader("Select sample groups"), # Empty at launch; populated when user opens modal - dbc.ModalBody(None, + dbc.ModalBody(get_select_lineages_modal_body(data), id="select-lineages-modal-body", style={"height": "50vh", "overflowY": "scroll"}), dbc.ModalFooter(get_select_lineages_modal_footer())