github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/ui/src/views/cluster/containers/nodesOverview/tableSection.tsx (about)

     1  // Copyright 2019 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  import * as React from "react";
    12  import { connect } from "react-redux";
    13  import cn from "classnames";
    14  import { Icon } from "antd";
    15  import { Action, Dispatch } from "redux";
    16  
    17  import { LocalSetting, setLocalSetting } from "src/redux/localsettings";
    18  import { AdminUIState } from "src/redux/state";
    19  import { Text, TextTypes } from "src/components";
    20  
    21  import "./tableSection.styl";
    22  
    23  interface MapStateToProps {
    24    isCollapsed: boolean;
    25  }
    26  
    27  interface MapDispatchToProps {
    28    saveExpandedState: (isCollapsed: boolean) => void;
    29  }
    30  
    31  interface TableSectionProps {
    32    // Uniq ID which is used to create LocalSettings key for storing user state in session.
    33    id: string;
    34    // Title of the section
    35    title: string;
    36    // Bottom part of the section, can be string or RectNode.
    37    footer?: React.ReactNode;
    38    // If true, allows collapse content of the section and only title remains visible.
    39    isCollapsible?: boolean;
    40    // Class which is applied on root element of the section.
    41    className?: string;
    42    children?: React.ReactNode;
    43  }
    44  
    45  interface TableSectionState {
    46    isCollapsed: boolean;
    47  }
    48  
    49  class TableSection extends React.Component<TableSectionProps & MapStateToProps & MapDispatchToProps, TableSectionState> {
    50    static defaultProps: Partial<TableSectionProps> = {
    51      isCollapsible: false,
    52      footer: null,
    53      className: "",
    54    };
    55  
    56    state = {
    57      isCollapsed: false,
    58    };
    59  
    60    componentWillUnmount() {
    61      this.props.saveExpandedState(this.state.isCollapsed);
    62    }
    63  
    64    onExpandSectionToggle = () => {
    65      this.setState({
    66        isCollapsed: !this.state.isCollapsed,
    67      });
    68      this.props.saveExpandedState(!this.state.isCollapsed);
    69    }
    70  
    71    getCollapseSectionToggle = () => {
    72      const { isCollapsible } = this.props;
    73      if (!isCollapsible) {
    74        return null;
    75      }
    76  
    77      const { isCollapsed } = this.state;
    78  
    79      return (
    80        <div className="collapse-toggle" onClick={this.onExpandSectionToggle}>
    81          <span>{isCollapsed ? "Show" : "Hide"}</span>
    82          <Icon
    83            className="collapse-toggle__icon"
    84            type={isCollapsed ? "caret-left" : "caret-down"} />
    85        </div>
    86      );
    87    }
    88  
    89    render() {
    90      const { children, title, footer, className } = this.props;
    91      const { isCollapsed } = this.state;
    92      const rootClass = cn("table-section", className);
    93      const contentClass = cn(
    94        "table-section__content",
    95        {
    96          "table-section__content--collapsed": isCollapsed,
    97        },
    98      );
    99      const collapseToggleButton = this.getCollapseSectionToggle();
   100  
   101      return (
   102        <div className={rootClass}>
   103          <section
   104            className="table-section__heading table-section__heading--justify-end">
   105            <Text textType={TextTypes.Heading3}>{title}</Text>
   106            {collapseToggleButton}
   107          </section>
   108          <div className={contentClass}>
   109            {children}
   110            {
   111              footer && (
   112                <div className="table-section__footer">
   113                  {footer}
   114                </div>
   115              )
   116            }
   117          </div>
   118        </div>
   119      );
   120    }
   121  }
   122  
   123  const getTableSectionKey = (id: string) => `cluster_overview/table_section/${id}/is_expanded`;
   124  
   125  const mapStateToProps = (state: AdminUIState, props: TableSectionProps) => {
   126    const tableSectionState = new LocalSetting<AdminUIState, boolean>(
   127      getTableSectionKey(props.id), (s) => s.localSettings,
   128    );
   129  
   130    return {
   131      isCollapsed: tableSectionState.selector(state),
   132    };
   133  };
   134  
   135  const mapDispatchToProps = (dispatch: Dispatch<Action, AdminUIState>, props: TableSectionProps) => ({
   136    saveExpandedState: (isCollapsed: boolean) => {
   137      const tableSectionKey = getTableSectionKey(props.id);
   138      dispatch(setLocalSetting(tableSectionKey, isCollapsed));
   139    },
   140  });
   141  
   142  export default connect(mapStateToProps, mapDispatchToProps)(TableSection);