Skip to content

Tree Component

Bruno P. Kinoshita edited this page Sep 9, 2020 · 22 revisions

A tree component to display hierarchical data.

Displays several TreeItem entries recursively. This recursion approach was based on the FreeCodeCamp Tree Browser implementation.

It keeps three cache collections (Sets), one for the TreeItem entries, one for the entries that are expanded, and one for the entries that are active.

The cache collections are used to avoid having to iterate all the entries for operations such as "Expand All" and "Collapse All", and were based on the Vuetify VTreeView component implementation.

Table of Contents

Requirements

This component utilizes the Cylc TreeItem component, as well as Vuetify components like VLayout, VFlex, etc.

Back to top

Data

treeItemCache

Cache of TreeItem entries. Updated whenever a TreeItem is added to the Tree (or recursively added to another TreeItem).

Back to top

activeCache

Cache of active entries (see prop activable). Updated whenever the active data property of a TreeItem changes.

Back to top

expandedCache

Cache of entries that were expanded (i.e. its children are now displayed to the user) (see data (expanded)[expanded]). Updated whenever the expanded prop property of a TreeItem changes.

Back to top

expanded

Whether the TreeItems added to the Tree must be initially expanded (true) or collapsed (false).

Back to top

expandFilter

A Function that is used by the method expandAll(#expandAll). When it is not null, expandAll uses this function to filter what entries are expanded or not.

Back to top

collapseFilter

A Function that is used by the method collapseAll(#collapseAll). When it is not null, collapseAll uses this function to filter what entries are collapsed or not.

Back to top

tasksFilter

An object with structure

tasksFilter: {
  name: '',
  states: []
}

that is used for filtering the tree. This object is bound to UI elements, such as text input field for the name, and a combobox for the filtered states.

But the filter may or may not be applied automatically. At the moment of writing, the user needs to press a button for the filter to be applied, to reduce the impact on the performance of the app.

activeFilters

This has a structure similar to tasksFilter. When the user enter values in the UI for the filters, those values are applied to tasksFilter. But when the user press the button to apply the filters, we move the filters over to this activeFilters data.

This way, the user can modify the filter parameters without changing the currently filtered tree. Until the button to apply the filters is pressed again.

Props

workflows

The main data structure. It is based on the response of a GraphQL query to retrieve workflows, but with a few modifications to the result.

In order to support recursion in the component, we need a fixed entry with the children nodes. Plus, in order to allow for customization based on the type of the node, it also requires a custom field __type.

  • type: Array
  • required: true
  • example:
[
  {
    __type: 'workflow',
    id: 'user/workflow1',
    name: 'workflow1',
    status: 'running',
    children: [
      {
        __type: 'checkpoint',
        id: '20100101T0000Z',
        name: '20100101T0000Z',
        state: 'failed',
        children: [
          {
            __type: 'task',
            id: 'user/workflow1/20100101T0000Z/foo',
            name: 'foo',
            state: 'failed',
            children: [
              {
                __type: 'job',
                id: 'user/workflow1/20100101T0000Z/foo/01',
                name: '#1',
                startedTime: '2019-08-19T22:44:42Z',
                state: 'failed',
                submitNum: 1
              }
            ]
          }
        ]
      }
    ]
  }
]

Back to top

hoverable

Whether each entry in the tree should be highlighted or not when the user hovers the mouse over it.

  • type: Boolean
  • default: false

Back to top

hoverable

Whether each entry in the tree should be highlighted or not when the user hovers the mouse over it.

  • type: Boolean
  • default: false

Back to top

activable

Whether clicking on the entry in the tree should mark it as active, changing its background color permanently until it is clicked again.

  • type: Boolean
  • default: false

Back to top

multipleActive

When enabled, users will be able to mark multiple entries in the tree as active, instead of a single one when activable is set to true.

  • type: Boolean
  • default: false

Back to top

Slots

We use only the default slot.

Back to top

Styles

See src/styles/cylc/_tree.scss

Back to top

Methods

These methods are used internally by the component. But can be used externally if necessary. There are multiple ways of accessing methods of a component externally, but one of the simplest is to assign a ref ID to the component when created. And then simply call the method.

Example.

<tree
    ref="treeComponent1"
    :workflows="workflowTree"
    :hoverable="hoverable"
    :activable="activable"
    :multiple-active="multipleActive"
></tree>

And then somewhere in your caller code, you can simply use something similar to <v-btn small @click="$refs.treeComponent1.expandAll()">Expand All</v-btn>.

expandAll (filter = null)

Expands all the entries of the Tree. If a filter is provided, the filter is applied first, and the expandedFilter is updated. The expandedCache is properly updated too.

Back to top

collapseAll (filter = null)

Collapses all the entries of the Tree. If a filter is provided, the filter is applied first, and the collapsedFilter is updated. The expandedCache is properly updated too (we only need to keep one cache, as we have the complete set domain values in treeItemCache).

Back to top

Other methods

The component has other methods such as onTreeItemExpanded, onTreeItemCollapsed, onTreeItemCreated, and onTreeItemClicked.

These methods react to events from TreeItem entries, and are not supposed to be extended or called directly.

Back to top

Unit tests

There are unit tests in the project for basic features, and for expanding and collapsing entries.

Back to top

Demo

Some of these screen shots/casts have been recorded during development, so they may differ a little.

Simple use case

This screen shot displays the Tree component rendering test data. Note that the workflow entry is not displayed.

Also note that cyclepoints use the Cylc Task component, but have a certain logic to choose what state represents the whole group (TODO: add link to page explaining logic).

Tasks use the same Task component. And jobs use the Cylc Job component. Jobs are displayed from the most recent submitted to the oldest. And the host name appears near the job icon (which has a color indicating its state).

Back to top

Responsive

What the component looks like when rendered in a browser with mobile viewport.

Back to top

Marking entries as active, and using methods to expand and collapse entries

In this example we have added a custom view with controls to customize the component (similar to Vuetify's show case sections).

Back to top

Summary information

When the user collapses a TreeItem that represents a task, the user is presented with the summary of the task jobs. As the jobs are now hidden (were collapsed), we show them aligned side-by-side next to the task entry.

Back to top

Clone this wiki locally