<commit_before>/*
 * Copyright 2018 Crown Copyright
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { compose, lifecycle } from 'recompose';
import Mousetrap from 'mousetrap';

import SplitPane from 'react-split-pane';
import PanelGroup from 'react-panelgroup';

import { Label, Table, Progress, Button, Input, Menu, Pagination } from 'semantic-ui-react';
import 'semantic-ui-css/semantic.min.css';

import { actionCreators, Directions, SortByOptions } from '../redux';
import { expressionActionCreators } from 'components/ExpressionBuilder';
import { fetchTrackers, TrackerSelection } from '../streamTasksResourceClient';
import TrackerDetails from '../TrackerDetails/TrackerDetails';
import { withConfig } from 'startup/config';

const {
  updateSort,
  updateTrackerSelection,
  moveSelection,
  resetPaging,
  updateSearchCriteria,
  changePage,
  pageRight,
  pageLeft,
} = actionCreators;

class TrackerDashboard extends Component {
  handleSort(newSortBy, currentSortBy, currentDirection) {
    if (currentSortBy === newSortBy) {
      if (currentDirection === Directions.ascending) {
        return this.props.onHandleSort(newSortBy, Directions.descending);
      }
      return this.props.onHandleSort(newSortBy, Directions.ascending);
    }
    return this.props.onHandleSort(newSortBy, Directions.ascending);
  }

  render() {
    const {
      trackers,
      sortBy,
      sortDirection,
      selectedTrackerId,
      searchCriteria,
      pageOffset,
      numberOfPages,
    } = this.props;
    const {
      onHandleTrackerSelection,
      onMoveSelection,
      onHandleSearchChange,
      onHandleSearch,
      onHandlePageChange,
      onHandlePageRight,
      onHandlePageLeft,
    } = this.props;

    const selectedTracker = trackers.find(tracker => tracker.filterId === selectedTrackerId);
    const showDetails = selectedTracker !== undefined;

    // TODO: At some point move the shortcuts to some common location;
    //       we will want to use the same binding for 'search' throughout.
    // Set up hotkeys to move the selection up and down
    Mousetrap.bind('up', () => onMoveSelection('up'));
    Mousetrap.bind('down', () => onMoveSelection('down'));
    Mousetrap.bind('right', () => onHandlePageRight());
    Mousetrap.bind('left', () => onHandlePageLeft());
    Mousetrap.bind('esc', () => onHandleTrackerSelection(undefined));
    Mousetrap.bind('ctrl+shift+f', () => this.searchInputRef.focus());
    Mousetrap.bind('enter', () => onHandleSearch());
    Mousetrap.bind('return', () => onHandleSearch());

    return (
      <div className="tracker-container">
        <Menu attached="top">
          <Menu.Menu position="left" className="search-container">
            <Input
              fluid
              placeholder="Search..."
              value={searchCriteria}
              onChange={(event, data) => onHandleSearchChange(data)}
              onKeyPress={(event, data) => onHandleSearch(event, data)}
              action={<Button onClick={() => onHandleSearch()}>Search</Button>}
              // We can set the ref to 'this', which means we can call this.searchInputRef.focus() elsewhere.
              ref={input => (this.searchInputRef = input)}
            />
          </Menu.Menu>
        </Menu>
        <PanelGroup direction="column" panelWidths={[{}, { minSize: 370 }]}>
          <div>
            <div
              id="table-container"
              className={`table-container${showDetails ? ' showing-details' : ''}`}
            >
              <Table selectable sortable basic="very" className="tracker-table" columns={15}>
                <Table.Header>
                  <Table.Row>
                    <Table.HeaderCell
                      sorted={sortBy === SortByOptions.pipelineUuid ? sortDirection : null}
                      onClick={() => this.handleSort(SortByOptions.pipeline, sortBy, sortDirection)}
                    >
                      Pipeline name
                    </Table.HeaderCell>
                    <Table.HeaderCell
                      sorted={sortBy === SortByOptions.priority ? sortDirection : null}
                      onClick={() => this.handleSort(SortByOptions.priority, sortBy, sortDirection)}
                    >
                      Priority
                    </Table.HeaderCell>
                    <Table.HeaderCell
                      sorted={sortBy === SortByOptions.progress ? sortDirection : null}
                      onClick={() => this.handleSort(SortByOptions.progress, sortBy, sortDirection)}
                    >
                      Progress
                    </Table.HeaderCell>
                  </Table.Row>
                </Table.Header>

                <Table.Body>
                  {trackers.map(({
                      pipelineName,
                      priority,
                      trackerPercent,
                      filterId,
                      createdOn,
                      createUser,
                      updateUser,
                      updatedOn,
                      enabled,
                      status,
                      lastPollAge,
                      taskCount,
                      trackerMs,
                      streamCount,
                      eventCount,
                    }, 
                  ) => (
                    <Table.Row
                      key={filterId}
                      className="tracker-row"
                      onClick={() => onHandleTrackerSelection(filterId, trackers)}
                      active={selectedTrackerId === filterId}
                    >
                      <Table.Cell className="name-column" textAlign="left" width={7}>
                        {pipelineName}
                      </Table.Cell>
                      <Table.Cell className="priority-column" textAlign="center" width={1}>
                        <Label circular color="green">
                          {priority}
                        </Label>
                      </Table.Cell>
                      <Table.Cell className="progress-column" width={7}>
                        <Progress indicating percent={trackerPercent} />
                      </Table.Cell>
                    </Table.Row>
                  ))}
                </Table.Body>
              </Table>
              <div className="pagination-container">
                <Pagination
                  activePage={pageOffset + 1}
                  totalPages={numberOfPages || 1}
                  firstItem={null}
                  lastItem={null}
                  size="tiny"
                  onPageChange={(event, data) => onHandlePageChange(data)}
                />
              </div>
            </div>
          </div>
          <TrackerDetails/>
        </PanelGroup>
      </div>
    );
  }
}

TrackerDashboard.contextTypes = {
  store: PropTypes.object.isRequired,
};

const mapStateToProps = state => ({<commit_msg>gh-787 -- Improve resizing<commit_after>/*
 * Copyright 2018 Crown Copyright
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { compose, lifecycle } from 'recompose';
import Mousetrap from 'mousetrap';

import SplitPane from 'react-split-pane';
import PanelGroup from 'react-panelgroup';

import { Label, Table, Progress, Button, Input, Menu, Pagination } from 'semantic-ui-react';
import 'semantic-ui-css/semantic.min.css';

import { actionCreators, Directions, SortByOptions } from '../redux';
import { expressionActionCreators } from 'components/ExpressionBuilder';
import { fetchTrackers, TrackerSelection } from '../streamTasksResourceClient';
import TrackerDetails from '../TrackerDetails/TrackerDetails';
import { withConfig } from 'startup/config';

const {
  updateSort,
  updateTrackerSelection,
  moveSelection,
  resetPaging,
  updateSearchCriteria,
  changePage,
  pageRight,
  pageLeft,
} = actionCreators;

class TrackerDashboard extends Component {
  handleSort(newSortBy, currentSortBy, currentDirection) {
    if (currentSortBy === newSortBy) {
      if (currentDirection === Directions.ascending) {
        return this.props.onHandleSort(newSortBy, Directions.descending);
      }
      return this.props.onHandleSort(newSortBy, Directions.ascending);
    }
    return this.props.onHandleSort(newSortBy, Directions.ascending);
  }

  render() {
    const {
      trackers,
      sortBy,
      sortDirection,
      selectedTrackerId,
      searchCriteria,
      pageOffset,
      numberOfPages,
    } = this.props;
    const {
      onHandleTrackerSelection,
      onMoveSelection,
      onHandleSearchChange,
      onHandleSearch,
      onHandlePageChange,
      onHandlePageRight,
      onHandlePageLeft,
    } = this.props;

    const selectedTracker = trackers.find(tracker => tracker.filterId === selectedTrackerId);
    const showDetails = selectedTracker !== undefined;
    // 370 is the minimum height because it lets all the tracker details be displayed
    const detailsPanelMinimumHeight = showDetails ? 370 : 0;
    const detailsPanelSize = showDetails ? null : 0;

    const panelSizes = [
      {},
      {
        resize: "dynamic",
        minSize: detailsPanelMinimumHeight,
        size: detailsPanelMinimumHeight
      },
    ];

    if (!showDetails) panelSizes[1].size = 0;

    // TODO: At some point move the shortcuts to some common location;
    //       we will want to use the same binding for 'search' throughout.
    // Set up hotkeys to move the selection up and down
    Mousetrap.bind('up', () => onMoveSelection('up'));
    Mousetrap.bind('down', () => onMoveSelection('down'));
    Mousetrap.bind('right', () => onHandlePageRight());
    Mousetrap.bind('left', () => onHandlePageLeft());
    Mousetrap.bind('esc', () => onHandleTrackerSelection(undefined));
    Mousetrap.bind('ctrl+shift+f', () => this.searchInputRef.focus());
    Mousetrap.bind('enter', () => onHandleSearch());
    Mousetrap.bind('return', () => onHandleSearch());

    return (
      <div className="tracker-container">
        <Menu attached="top">
          <Menu.Menu position="left" className="search-container">
            <Input
              fluid
              placeholder="Search..."
              value={searchCriteria}
              onChange={(event, data) => onHandleSearchChange(data)}
              onKeyPress={(event, data) => onHandleSearch(event, data)}
              action={<Button onClick={() => onHandleSearch()}>Search</Button>}
              // We can set the ref to 'this', which means we can call this.searchInputRef.focus() elsewhere.
              ref={input => (this.searchInputRef = input)}
            />
          </Menu.Menu>
        </Menu>
        <PanelGroup direction="column" panelWidths={panelSizes}>
          <div>
            <div
              id="table-container"
              className={`table-container${showDetails ? ' showing-details' : ''}`}
            >
              <Table selectable sortable basic="very" className="tracker-table" columns={15}>
                <Table.Header>
                  <Table.Row>
                    <Table.HeaderCell
                      sorted={sortBy === SortByOptions.pipelineUuid ? sortDirection : null}
                      onClick={() => this.handleSort(SortByOptions.pipeline, sortBy, sortDirection)}
                    >
                      Pipeline name
                    </Table.HeaderCell>
                    <Table.HeaderCell
                      sorted={sortBy === SortByOptions.priority ? sortDirection : null}
                      onClick={() => this.handleSort(SortByOptions.priority, sortBy, sortDirection)}
                    >
                      Priority
                    </Table.HeaderCell>
                    <Table.HeaderCell
                      sorted={sortBy === SortByOptions.progress ? sortDirection : null}
                      onClick={() => this.handleSort(SortByOptions.progress, sortBy, sortDirection)}
                    >
                      Progress
                    </Table.HeaderCell>
                  </Table.Row>
                </Table.Header>

                <Table.Body>
                  {trackers.map(({
                      pipelineName,
                      priority,
                      trackerPercent,
                      filterId,
                      createdOn,
                      createUser,
                      updateUser,
                      updatedOn,
                      enabled,
                      status,
                      lastPollAge,
                      taskCount,
                      trackerMs,
                      streamCount,
                      eventCount,
                    }) => (
                      <Table.Row
                        key={filterId}
                        className="tracker-row"
                        onClick={() => onHandleTrackerSelection(filterId, trackers)}
                        active={selectedTrackerId === filterId}
                      >
                        <Table.Cell className="name-column" textAlign="left" width={7}>
                          {pipelineName}
                        </Table.Cell>
                        <Table.Cell className="priority-column" textAlign="center" width={1}>
                          <Label circular color="green">
                            {priority}
                          </Label>
                        </Table.Cell>
                        <Table.Cell className="progress-column" width={7}>
                          <Progress indicating percent={trackerPercent} />
                        </Table.Cell>
                      </Table.Row>
                    ))}
                </Table.Body>
              </Table>
              <div className="pagination-container">
                <Pagination
                  activePage={pageOffset + 1}
                  totalPages={numberOfPages || 1}
                  firstItem={null}
                  lastItem={null}
                  size="tiny"
                  onPageChange={(event, data) => onHandlePageChange(data)}
                />
              </div>
            </div>
          </div>
          <TrackerDetails />
        </PanelGroup>
      </div>
    );
  }
}

TrackerDashboard.contextTypes = {
  store: PropTypes.object.isRequired,
};

const mapStateToProps = state => ({
{'fraction_non_alphanumeric': 0.1069935018979605, 'fraction_numerical': 0.0029595316219520043, 'mean_word_length': 1.7692855870301087, 'pattern_counts': {'":': 0, '<': 91, '<?xml version=': 0, '>': 131, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4643697', 'n_tokens_mistral': 3911, 'n_tokens_neox': 3764, 'n_words': 890}