Commit f490b7ff authored by Duggan, John's avatar Duggan, John
Browse files

Refactor revo_grid.js to use classes

parent e1a0415f
Loading
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -159,6 +159,8 @@ class DataSelectorModel:
        if not self.state.user_directory:
            return None

        # We don't want to pull all user directory content as there can be an extremely large amount of content.
        # To deal with this, we make an assumption that anything the user wants exposed is placed in the nova directory.
        return Path("/SNS/users") / self.state.user_directory / "nova"

    def get_directories(self) -> List[str]:
+14 −8
Original line number Diff line number Diff line
@@ -52,7 +52,7 @@ class DataSelector(datagrid.VGrid):
            If unset, the `all` strategy will be used.
        show_user_directories : bool, optional
            Whether or not to allow users to select data files from user directories. Ignored if the facility parameter
            is set.
            is set. Please note that the component only looks for a "nova" directory and ignores all other content.
        **kwargs
            All other arguments will be passed to the underlying
            `VDataTable component <https://trame.readthedocs.io/en/latest/trame.widgets.vuetify3.html#trame.widgets.vuetify3.VDataTable>`_.
@@ -89,7 +89,7 @@ class DataSelector(datagrid.VGrid):

        self._flush_state = f"flushState('{self._v_model_name_in_state}');"
        self._reset_rv_grid = client.JSEval(
            exec=f"window.rvUpdateCheckboxes('{self._v_model}', '{self._datafiles_name}')"
            exec=f"window.grid_manager.get('{self._revogrid_id}').updateCheckboxes()"
        ).exec
        self._reset_state = client.JSEval(exec=f"{self._v_model} = []; {self._flush_state}").exec

@@ -144,13 +144,12 @@ class DataSelector(datagrid.VGrid):
                    can_focus=False,
                    columns=(
                        "[{"
                        "    cellTemplate: (createElement, props) => window.rvCellTemplate(createElement, props),"
                        "    columnTemplate: (createElement, props) => window.rvColumnTemplate(createElement, props),"
                        f"   datafiles_key: '{self._datafiles_name}',"
                        f"   model_key: '{self._v_model}',"
                        "    cellTemplate: (createElement, props) =>"
                        f"       window.grid_manager.get('{self._revogrid_id}').cellTemplate(createElement, props),"
                        "    columnTemplate: (createElement) =>"
                        f"       window.grid_manager.get('{self._revogrid_id}').columnTemplate(createElement),"
                        "    name: 'Available Datafiles',"
                        "    prop: 'title',"
                        f"   state_key: '{self._v_model_name_in_state}',"
                        "}]",
                    ),
                    frame_size=10,
@@ -170,7 +169,14 @@ class DataSelector(datagrid.VGrid):
                # Sets up some JavaScript event handlers when the component is mounted.
                with self:
                    client.ClientTriggers(
                        mounted=f"window.rvOnMount('{self._revogrid_id}', '{self._v_model}', '{self._datafiles_name}');"
                        mounted=(
                            "window.grid_manager.add("
                            f"  '{self._revogrid_id}',"
                            f"  '{self._v_model}',"
                            f"  '{self._datafiles_name}',"
                            f"  '{self._v_model_name_in_state}'"
                            ")"
                        )
                    )

            with cast(
+97 −72
Original line number Diff line number Diff line
window.rvOnMount = function(id, modelKey, dataKey) {
    const grid = document.querySelector(`#${id}`)
    grid.addEventListener('viewportscroll', () => {
        window.rvUpdateCheckboxes(modelKey, dataKey)
class RevoGrid {
    constructor(id, modelKey, dataKey, stateKey) {
        this.id = id
        this.modelKey = modelKey
        this.dataKey = dataKey
        this.stateKey = stateKey

        this.grid = document.querySelector(`#${this.id}`)
        this.grid.addEventListener('viewportscroll', () => {
            this.updateCheckboxes()
        })
    }

window.rvUpdateCheckboxes = function(modelKey, dataKey) {
    updateCheckboxes() {
        const trameState = window.trame.state.state
    const modelValue = _.get(trameState, modelKey)
    const availableData = _.get(trameState, dataKey)
    const selectAllCheckbox = document.querySelector(".header-content input")
    const rowCheckboxes = document.querySelectorAll(".rgCell")
        const modelValue = _.get(trameState, this.modelKey)
        const availableData = _.get(trameState, this.dataKey)
        const selectAllCheckbox = this.grid.querySelector(".header-content input")
        const rowCheckboxes = this.grid.querySelectorAll(".rgCell")

        if (selectAllCheckbox === null) {
            return
@@ -28,55 +34,74 @@ window.rvUpdateCheckboxes = function(modelKey, dataKey) {
        }

        rowCheckboxes.forEach((element) => {
        input = element.querySelector('input')
        rowIndex = element.dataset.rgrow
            const input = element.querySelector('input')

            const rowIndex = element.dataset.rgrow
            input.checked = modelValue.includes(availableData[rowIndex].path)
        })
    }

window.rvCellTemplate = function(createElement, props) {
    cellTemplate(createElement, props) {
        const inputVNode = createElement('input', {
            type: 'checkbox',
            onChange: (e) => {
                const trameState = window.trame.state.state
            const modelValue = _.get(trameState, props.column.model_key)
                const modelValue = _.get(trameState, this.modelKey)
                const path = props.data[props.rowIndex].path
                const index = modelValue.indexOf(path)

                // We need to assign instead of modifying in place in order for the Trame watcher to pick up changes.
                if (e.target.checked && index < 0) {
                _.set(trameState, props.column.model_key, _.concat(modelValue, path))
                    _.set(trameState, this.modelKey, _.concat(modelValue, path))
                } else if (index >= 0) {
                _.set(trameState, props.column.model_key, modelValue.toSpliced(index, 1))
                    _.set(trameState, this.modelKey, modelValue.toSpliced(index, 1))
                }

                // Update the UI
            window.rvUpdateCheckboxes(props.column.model_key, props.column.datafiles_key)
            window.trame.state.dirty(props.column.state_key)
                this.updateCheckboxes(this.modelKey, this.dataKey)
                window.trame.state.dirty(this.stateKey)
            },
        })

        return createElement('label', undefined, inputVNode, props.model[props.prop])
    }

window.rvColumnTemplate = function (createElement, props) {
    columnTemplate(createElement) {
        const inputVNode = createElement('input', {
            type: 'checkbox',
            onChange: (e) => {
                const trameState = window.trame.state.state
            const availableData = _.get(trameState, props.datafiles_key)
                const availableData = _.get(trameState, this.dataKey)

                if (e.target.checked) {
                _.set(trameState, props.model_key, availableData.map((item) => item.path))
                    _.set(trameState, this.modelKey, availableData.map((item) => item.path))
                } else {
                _.set(trameState, props.model_key, [])
                    _.set(trameState, this.modelKey, [])
                }

                // Update the UI
            window.rvUpdateCheckboxes(props.model_key, props.datafiles_key)
            window.trame.state.dirty(props.state_key)
                this.updateCheckboxes(this.modelKey, this.dataKey)
                window.trame.state.dirty(this.stateKey)
            },
        })

        console.log(inputVNode)
        return [inputVNode, 'Available Datafiles']
    }
}

class RevoGridManager {
    constructor() {
        this.grids = {}
    }

    add(id, modelKey, dataKey, stateKey) {
        this.grids[id] = new RevoGrid(id, modelKey, dataKey, stateKey)
    }

    get(id) {
        return this.grids[id]
    }
}

window.grid_manager = new RevoGridManager()