private void initTableColumns() {
        // Info column.
        final InfoColumn<NodeStatusResult> infoColumn = new InfoColumn<NodeStatusResult>() {
            @Override
            protected void showInfo(final NodeStatusResult row, final PopupPosition popupPosition) {
                nodeManager.info(
                        row.getNode().getName(),
                        result -> showNodeInfoResult(row.getNode(), result, popupPosition),
                        error -> showNodeInfoError(error.getException(), popupPosition),
                        NodeListPresenter.this);
            }
        };
        dataGrid.addColumn(infoColumn, "<br/>", ColumnSizeConstants.ICON_COL);

        // Name.
        dataGrid.addResizableColumn(
                DataGridUtil.textColumnBuilder(DataGridUtil.toStringFunc(NodeStatusResult::getNode, Node::getName))
                        .enabledWhen(NodeListPresenter::isNodeEnabled)
                        .withSorting(FindNodeStatusCriteria.FIELD_ID_NAME)
                        .build(),
                DataGridUtil.headingBuilder("Name")
                        .withToolTip("The name of the node as defined in configuration.")
                        .build(),
                300);

        // Host Name.
        dataGrid.addResizableColumn(
                DataGridUtil.textColumnBuilder((NodeStatusResult result) -> NullSafe.get(
                                result,
                                NodeStatusResult::getNode,
                                Node::getUrl))
                        .enabledWhen(NodeListPresenter::isNodeEnabled)
                        .withSorting(FindNodeStatusCriteria.FIELD_ID_URL)
                        .build(),
                DataGridUtil.headingBuilder("Cluster Base Endpoint")
                        .withToolTip("The base URL for the node.")
                        .build(),
                300);

        // Version
        dataGrid.addResizableColumn(
                DataGridUtil.textColumnBuilder((NodeStatusResult result) -> NullSafe.get(
                                result,
                                NodeStatusResult::getNode,
                                Node::getBuildVersion))
                        .enabledWhen(NodeListPresenter::isNodeEnabled)
                        .withSorting(FindNodeStatusCriteria.FIELD_ID_BUILD_VERSION)
                        .build(),
                DataGridUtil.headingBuilder("Build Version")
                        .withToolTip("The version of Stroom that the node is running.")
                        .build(),
                150);

        // Ping (ms)
        dataGrid.addResizableColumn(
                DataGridUtil.columnBuilder(
                                this::getPingBarSafeHtml,
                                SafeHtmlCell::new)
                        .enabledWhen(NodeListPresenter::isNodeEnabled)
                        .build(),
                DataGridUtil.headingBuilder("Ping (ms)")
                        .withToolTip("The time in milliseconds to get a response back from the node.")
                        .build(),
                250);

        // Last Boot Time
        dataGrid.addColumn(
                DataGridUtil.textColumnBuilder(this::extractLastBootTimeAsStr)
                        .enabledWhen(NodeListPresenter::isNodeEnabled)
                        .withSorting(FindNodeStatusCriteria.FIELD_ID_LAST_BOOT_MS)
                        .build(),
                DataGridUtil.headingBuilder("Up Date")
                        .withToolTip("The time that the node last started up whether currently running or not.")
                        .build(),
                ColumnSizeConstants.DATE_AND_DURATION_COL);

        // Master.
        dataGrid.addColumn(
                DataGridUtil.readOnlyTickBoxColumnBuilder(TickBoxState.createTickBoxFunc(
                                (NodeStatusResult result) -> NullSafe.get(
                                        result,
                                        NodeStatusResult::isMaster)))
                        .enabledWhen(NodeListPresenter::isNodeEnabled)
                        .centerAligned()
                        .build(),
                DataGridUtil.headingBuilder("Master")
                        .withToolTip("Whether the node has been assigned as the master node for the cluster.")
                        .centerAligned()
                        .build(),
                60);

        // Priority.
        dataGrid.addColumn(
                DataGridUtil.valueSpinnerColumnBuilder(NodeListPresenter::extractNodePriority,
                                1L,
                                100L)
                        .enabledWhen(NodeListPresenter::isNodeEnabled)
                        .withSorting(FindNodeStatusCriteria.FIELD_ID_PRIORITY)
                        .withFieldUpdater((rowIndex, nodeStatusResult, value) ->
                                nodeManager.setPriority(
                                        nodeStatusResult.getNode().getName(),
                                        value.intValue(),
                                        result -> internalRefresh(),
                                        this))
                        .build(),
                DataGridUtil.headingBuilder("Priority")
                        .withToolTip("Defines how important the node is when it comes to " +
                                     "assigning a master. The larger the number the more chance it will become " +
                                     "the master.")
                        .build(),
                80);

        // Enabled
        dataGrid.addColumn(
                DataGridUtil.updatableTickBoxColumnBuilder(TickBoxState.createTickBoxFunc(
                                (NodeStatusResult result) -> NullSafe.get(
                                        result,
                                        NodeStatusResult::getNode,
                                        Node::isEnabled)))
                        .enabledWhen(NodeListPresenter::isNodeEnabled)
                        .withSorting(FindNodeStatusCriteria.FIELD_ID_ENABLED)
                        .withFieldUpdater((index, row, value) -> {
                            if (row != null) {
                                final String nodeName = row.getNode().getName();
                                nodeManager.setEnabled(
                                        nodeName,
                                        value.toBoolean(),
                                        result -> {
                                            internalRefresh();
                                            NodeChangeEvent.fire(NodeListPresenter.this, nodeName);
                                        },
                                        this);
                            }
                        })
                        .centerAligned()
                        .build(),
                DataGridUtil.headingBuilder("Enabled")
                        .withToolTip("Whether the node is enabled for processing and background jobs.")
                        .centerAligned()
                        .build(),
                ColumnSizeConstants.ENABLED_COL);

        DataGridUtil.addEndColumn(dataGrid);
    }
Add the columns to the table.
stroom-core-client/src/main/java/stroom/node/client/presenter/NodeListPresenter.java