expandedKeys: getExpandedKeys()

in client/src/components/pipelines/PipelinesLibrary.js [319:609]


            expandedKeys: getExpandedKeys(rootItems),
            filter: this.props.hiddenObjectsTreeFilter()
          }
        );
        item.isLeaf = !item.children || item.children.length === 0;
        item.childrenMetadataLoaded = true;
      } else if (item.type === ItemTypes.folder && item.children.length === 0) {
        item.isLeaf = true;
      } else if (item.type === ItemTypes.version) {
        item.isLeaf = true;
      }
      setState({rootItems});
      resolve();
    });
  };

  renderItemTitle (item) {
    let icon;
    const subIcon = item.locked ? 'lock' : undefined;
    let sensitive = false;
    let subTitle;
    let iconStyle = {};
    let iconClassName;
    switch (item.type) {
      case ItemTypes.pipeline: icon = 'fork'; break;
      case ItemTypes.versionedStorage:
        icon = 'inbox';
        iconClassName = 'cp-versioned-storage';
        break;
      case ItemTypes.folder:
        if (item.id === 'pipelines') {
          icon = 'fork';
        } else if (item.id === 'storages') {
          icon = 'inbox';
        } else if (item.isProject || (item.objectMetadata && item.objectMetadata.type &&
          (item.objectMetadata.type.value || '').toLowerCase() === 'project')) {
          icon = 'solution';
        } else {
          icon = 'folder';
        }
        break;
      case ItemTypes.version: icon = 'tag'; break;
      case ItemTypes.storage:
        if (item.storageType && item.storageType.toLowerCase() !== 'nfs') {
          icon = 'inbox';
        } else {
          icon = 'hdd';
        }
        sensitive = item.sensitive;
        subTitle = (
          <AWSRegionTag
            className={styles.regionFlags}
            regionId={item.regionId}
          />
        );
        break;
      case ItemTypes.configuration: icon = 'setting'; break;
      case ItemTypes.metadataFolder: icon = 'appstore-o'; break;
      case ItemTypes.metadata: icon = 'appstore-o'; break;
      case ItemTypes.projectHistory: icon = 'clock-circle-o'; break;
    }
    let name = item.type === ItemTypes.metadata ? `${item.name} [${item.amount}]` : item.name;
    if (item.searchResult) {
      name = (
        <span>
          <span>{item.name.substring(0, item.searchResult.index)}</span>
          <span className={classNames(styles.searchResult, 'cp-search-highlight-text')}>
            {
              item.name.substring(
                item.searchResult.index,
                item.searchResult.index + item.searchResult.length
              )
            }
          </span>
          <span>{item.name.substring(item.searchResult.index + item.searchResult.length)}</span>
        </span>
      );
    }
    let treeItemTitleClassName = styles.treeItemTitle;
    if (item.type === ItemTypes.folder && item.locked) {
      treeItemTitleClassName = `${styles.treeItemTitle} ${styles.readonly}`;
    }
    return (
      <span
        id={`pipelines-library-tree-node-${item.key}-name`}
        className={treeItemTitleClassName}>
        {
          icon && (
            <Icon
              type={icon}
              className={classNames({'cp-sensitive': sensitive}, iconClassName)}
              style={iconStyle}
            />
          )
        }
        {
          subIcon && (
            <Icon
              type={subIcon}
              className={classNames({'cp-sensitive': sensitive}, iconClassName)}
              style={iconStyle}
            />
          )
        }
        <span className="name">{name}</span>
        {subTitle}
      </span>
    );
  }

  generateTreeItems (items) {
    return formatTreeItems(items, {preferences: this.props.preferences})
      .map(item => {
        if (item.isLeaf) {
          return (
            <Tree.TreeNode
              className={`pipelines-library-tree-node-${item.key}`}
              title={this.renderItemTitle(item)}
              key={item.key}
              isLeaf={item.isLeaf}
            />
          );
        } else {
          return (
            <Tree.TreeNode
              className={`pipelines-library-tree-node-${item.key}`}
              title={this.renderItemTitle(item)}
              key={item.key}
              isLeaf={item.isLeaf}>
              {this.generateTreeItems(item.children)}
            </Tree.TreeNode>
          );
        }
      });
  }

  generateTree () {
    return (
      <Tree
        className={`${styles.libraryTree} pipeline-library`}
        onSelect={this.onSelect}
        onExpand={this.onExpand}
        checkStrictly
        loadData={this.loadData}
        draggable
        onDragStart={this.onDragStart}
        onDrop={this.onDrop}
        expandedKeys={this.state.expandedKeys}
        selectedKeys={this.state.selectedKeys} >
        {this.generateTreeItems(this.state.rootItems)}
      </Tree>
    );
  }

  onSearch = async (text) => {
    await search(text, this.state.rootItems);
    const expandedKeys = getExpandedKeys(this.state.rootItems);
    this.setState({expandedKeys});
  };

  @observable _paneWidth;

  initializeSplitPane = (splitPane) => {
    if (!splitPane) {
      return;
    }
    this._paneWidth = splitPane.splitPane.offsetWidth;
  };

  renderLibrary () {
    return (
      <Card
        id="pipelines-library-tree-container"
        style={{overflowY: 'auto'}}
        className={
          classNames(
            styles.libraryCard,
            'cp-panel',
            'cp-panel-no-hover',
            'cp-panel-borderless'
          )
        }
        bodyStyle={{padding: 0}}>
        <Row
          type="flex"
          justify="space-between"
          align="middle"
          className={styles.headerRow}>
          <span className={styles.title}>
            Library
          </span>
        </Row>
        <Row id="pipelines-library-tree-search-container" className={styles.searchRow}>
          <Input.Search
            id="pipelines-library-search-input"
            placeholder="Search"
            onSearch={this.onSearch} />
        </Row>
        <Row id="pipelines-library-tree">
          <canvas
            id="drag-placeholder"
            style={{backgroundColor: 'transparent', width: 1, height: 1, position: 'absolute'}}
          />
          {this.generateTree()}
        </Row>
      </Card>
    );
  }

  render () {
    if (!this.props.uiNavigation.libraryExpanded) {
      return (
        <PipelinesLibraryContent
          location={this.props.path}
          query={this.props.query}
          onReloadTree={
            (reloadRoot, folder) => this.reloadTree(
              reloadRoot === undefined ? true : reloadRoot,
              folder
            )
          }
          style={{overflow: 'auto'}}
        >
          {this.props.children}
        </PipelinesLibraryContent>
      );
    }

    return (
      <Row id="pipelines-library-container" className={styles.container}>
        <SplitPane
          className="pipelines-library-split-pane"
          ref={this.initializeSplitPane}
          split="vertical"
          minSize={100}
          maxSize={this._paneWidth ? this._paneWidth / 2.0 : 400}
          defaultSize="15%"
          pane1Style={{overflowY: 'auto', display: 'flex', flexDirection: 'column'}}
          pane2Style={{
            overflowY: 'auto',
            overflowX: 'hidden',
            display: 'flex',
            flexDirection: 'column'
          }}
          resizerClassName="cp-split-panel-resizer"
          resizerStyle={{
            width: 8,
            margin: 0,
            cursor: 'col-resize',
            boxSizing: 'border-box',
            backgroundClip: 'padding',
            zIndex: 1
          }}>
          <div id="pipelines-library-split-pane-left" className={styles.subContainer}>
            {this.renderLibrary()}
          </div>
          <div id="pipelines-library-split-pane-right" className={styles.subContainer}>
            <PipelinesLibraryContent
              location={this.props.path}
              query={this.props.query}
              onReloadTree={
                (reloadRoot, folder) => this.reloadTree(
                  reloadRoot === undefined ? true : reloadRoot,
                  folder
                )
              }
            >
              {this.props.children}
            </PipelinesLibraryContent>
          </div>
        </SplitPane>
      </Row>
    );
  }

  async reloadItem (key, expand, rootItems, reloadRoot = true) {
    if (!key) {
      return;
    }
    if (!rootItems) {
      rootItems = this.state.rootItems;
    }
    const item = getTreeItemByKey(key, rootItems);
    if (!item) {
      return;
    }
    switch (item.type) {
      case ItemTypes.folder:
      case ItemTypes.projectHistory:
        if (item.id === 'root') {
          if (reloadRoot) {