Control whether a custom tool is enabled or disabled

I have made an app using both bokeh and flask that queries a timestream database and renders the data using bokeh. The data is used to produce 4 dictionaries which store different resolutions of the data which are swapped into the columndatasource depending on the zoom level.

I have created a custom tool to download the raw data that is present in one of the 4 dictionaries but I would like for the tool to show as disabled when the column datasource is empty. Similar to the undo tool when the undo stack is empty:

image

Here is the implementation of my custom tool:

from bokeh.core.properties import Dict, Either, Float, List, Nullable, String
from bokeh.models import Tool
from bokeh.util.compiler import TypeScript

TS_CODE = r"""
import {ActionTool, ActionToolView} from "models/tools/actions/action_tool"
import * as p from "core/properties"
import * as t from "core/types"

export class DownloadDataToolView extends ActionToolView {
    model: DownloadDataTool

 doit(): void {
        interface Data {
            [key: string]: any[]
            date: any[]
            value: any[]
        }

        const data = <Data>this.model.source
        
        if (data === null) {
            return
        }
        
        const headers = Object.keys(data)
        let csvContent = headers.join(",") + "\n"
        const filename = "data.csv"

        for (let i = 0; i < headers.map(header => data[header].length).reduce((a, b) => Math.max(a, b), 0); i++) {
                const row = headers.map(header => (data[header][i] !== undefined ? data[header][i] : "")).join(",")
                csvContent += row + "\n"
        }

        const blob = new Blob([csvContent], { type: "text/csv;charset=utf-8;" })
        const link = document.createElement("a")

        link.href = URL.createObjectURL(blob)
        link.download = filename
        link.target = "_blank"
        link.style.visibility = 'hidden'
        link.dispatchEvent(new MouseEvent('click'))
        
 }
}

export namespace DownloadDataTool {
    export type Attrs = p.AttrsOf<Props>

    export type Props = ActionTool.Props & {
        source: p.Property<t.Dict<t.Arrayable<number>> | null>
    }
}

export interface DownloadDataTool extends DownloadDataTool.Attrs {}

export class DownloadDataTool extends ActionTool {
    properties: DownloadDataTool.Props
    __view_type__: DownloadDataToolView

    constructor(attrs?: Partial<DownloadDataTool.Attrs>) {
        super(attrs)
    }

    tool_name = "Download Data"
    default_order = 1

    static {
        this.prototype.default_view = DownloadDataToolView

        this.define<DownloadDataTool.Props>(({Dict, Arrayable, Nullable, Number}) => ({
            source: [ Nullable(Dict(Arrayable(Number))), null ],
        }))
    }
}
"""


class DownloadDataTool(Tool):
    __implementation__ = TypeScript(TS_CODE)
    source = Nullable(Dict(String, List(Either(Float, String))))

Any help would be greatly appreciated!

There is not currently any enabled / disabled functionality for toolbar icons. In the short term, as an alternative, you could toggle the tool’s visisble property on and off. Otherwise, feel free to open a GitHub Issue to propose something for future feature development.

Hi Bryan, with some experimenting I was able to achieve the functionality that I was looking for.

I added this to the top of my class declaration:

    connect_signals(): void {
        super.connect_signals()
        this.connect(this.model.properties.source.change, () => {
            this.model.disabled = this.model.source === null
        })
    }

As well as overriding the initial enabled/disabled state:

this.override<DownloadDataTool.Props>({
    disabled: true,
})

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.