<commit_before>// @flow
/* eslint-disable jsx-a11y/href-no-hash */

import _ from "lodash";
import * as React from "react";
import { Link, withRouter } from "react-router-dom";
import Request from "libs/request";
import { AsyncLink } from "components/async_clickables";
import { Spin, Input, Table, Button, Modal, Tag } from "antd";
import type { APIAnnotationType } from "admin/api_flow_types";
import FormatUtils from "libs/format_utils";
import Toast from "libs/toast";
import Utils from "libs/utils";
import update from "immutability-helper";
import TemplateHelpers from "libs/template_helpers";
import EditableTextLabel from "oxalis/view/components/editable_text_label";
import EditableTextIcon from "oxalis/view/components/editable_text_icon";
import FileUpload from "components/file_upload";
import type { ReactRouterHistoryType } from "react_router";

const { Column } = Table;
const { Search } = Input;

type Props = {
  userId: ?string,
  isAdminView: boolean,
  history: ReactRouterHistoryType,
};

type State = {
  shouldShowArchivedTracings: boolean,
  archivedTracings: Array<APIAnnotationType>,
  unarchivedTracings: Array<APIAnnotationType>,
  didAlreadyFetchMetaInfo: {
    isArchived: boolean,
    isUnarchived: boolean,
  },
  searchQuery: string,
  isUploadingNML: boolean,
  tags: Array<string>,
  isLoading: boolean,
};

class ExplorativeAnnotationsView extends React.PureComponent<Props, State> {
  state = {
    shouldShowArchivedTracings: false,
    archivedTracings: [],
    unarchivedTracings: [],
    didAlreadyFetchMetaInfo: {
      isArchived: false,
      isUnarchived: false,
    },
    searchQuery: "",
    isUploadingNML: false,
    tags: [],
    isLoading: false,
  };

  componentDidMount() {
    this.restoreSearchTags();
    this.fetchDataMaybe();
  }

  isFetchNecessary(): boolean {
    const accessor = this.state.shouldShowArchivedTracings ? "isArchived" : "isUnarchived";
    return !this.state.didAlreadyFetchMetaInfo[accessor];
  }

  restoreSearchTags() {
    // restore the search query tags from the last session
    const searchTagString = localStorage.getItem("lastDashboardSearchTags");
    if (searchTagString) {
      try {
        const searchTags = JSON.parse(searchTagString);
        this.setState({ tags: searchTags });
      } catch (error) {
        // pass
      }
    }
  }

  async fetchDataMaybe(): Promise<void> {
    if (!this.isFetchNecessary()) {
      return;
    }

    const isFinishedString = this.state.shouldShowArchivedTracings.toString();
    const url = this.props.userId
      ? `/api/users/${this.props.userId}/annotations?isFinished=${isFinishedString}`
      : `/api/user/annotations?isFinished=${isFinishedString}`;

    this.setState({ isLoading: true });
    const tracings = await Request.receiveJSON(url);
    if (this.state.shouldShowArchivedTracings) {
      this.setState(
        update(this.state, {
          isLoading: { $set: false },
          archivedTracings: { $set: tracings },
          didAlreadyFetchMetaInfo: {
            isArchived: { $set: true },
          },
        }),
      );
    } else {
      this.setState(
        update(this.state, {
          isLoading: { $set: false },
          unarchivedTracings: { $set: tracings },
          didAlreadyFetchMetaInfo: {
            isUnarchived: { $set: true },
          },
        }),
      );
    }
  }

  toggleShowArchived = () => {
    this.setState({ shouldShowArchivedTracings: !this.state.shouldShowArchivedTracings }, () => {
      this.fetchDataMaybe();
    });
  };

  finishOrReopenTracing = async (type: "finish" | "reopen", tracing: APIAnnotationType) => {
    const url =
      type === "finish"
        ? `/annotations/${tracing.typ}/${tracing.id}/finish`
        : `/annotations/${tracing.typ}/${tracing.id}/reopen`;

    const newTracing = await Request.receiveJSON(url);
    Toast.messages(newTracing.messages);

    const newTracings = this.getCurrentTracings().filter(t => t.id !== tracing.id);

    if (type === "finish") {
      this.setState({
        unarchivedTracings: newTracings,
        archivedTracings: [newTracing].concat(this.state.archivedTracings),
      });
    } else {
      this.setState({
        archivedTracings: newTracings,
        unarchivedTracings: [newTracing].concat(this.state.unarchivedTracings),
      });
    }
  };

  handleNMLUpload = (response: Object) => {
    response.messages.map(m => Toast.success(m.success));
    this.props.history.push(`/annotations/${response.annotation.typ}/${response.annotation.id}`);
  };

  renderActions = (tracing: APIAnnotationType) => {
    if (tracing.typ !== "Explorational") {
      return null;
    }

    const { typ, id } = tracing;
    if (!this.state.shouldShowArchivedTracings) {
      return (
        <div>
          <Link to={`/annotations/${typ}/${id}`}>
            <i className="fa fa-random" />
            <strong>Trace</strong>
          </Link>
          <br />
          <Link to={`/annotations/${typ}/${id}/download`}>
            <i className="fa fa-download" />
            Download
          </Link>
          <br />
          <AsyncLink href="#" onClick={() => this.finishOrReopenTracing("finish", tracing)}>
            <i className="fa fa-archive" />
            Archive
          </AsyncLink>
          <br />
        </div>
      );
    } else {
      return (
        <div>
          <AsyncLink href="#" onClick={() => this.finishOrReopenTracing("reopen", tracing)}><commit_msg>fixed tracing download link in dashboard<commit_after>// @flow
/* eslint-disable jsx-a11y/href-no-hash */

import _ from "lodash";
import * as React from "react";
import { Link, withRouter } from "react-router-dom";
import Request from "libs/request";
import { AsyncLink } from "components/async_clickables";
import { Spin, Input, Table, Button, Modal, Tag } from "antd";
import type { APIAnnotationType } from "admin/api_flow_types";
import FormatUtils from "libs/format_utils";
import Toast from "libs/toast";
import Utils from "libs/utils";
import update from "immutability-helper";
import TemplateHelpers from "libs/template_helpers";
import EditableTextLabel from "oxalis/view/components/editable_text_label";
import EditableTextIcon from "oxalis/view/components/editable_text_icon";
import FileUpload from "components/file_upload";
import type { ReactRouterHistoryType } from "react_router";

const { Column } = Table;
const { Search } = Input;

type Props = {
  userId: ?string,
  isAdminView: boolean,
  history: ReactRouterHistoryType,
};

type State = {
  shouldShowArchivedTracings: boolean,
  archivedTracings: Array<APIAnnotationType>,
  unarchivedTracings: Array<APIAnnotationType>,
  didAlreadyFetchMetaInfo: {
    isArchived: boolean,
    isUnarchived: boolean,
  },
  searchQuery: string,
  isUploadingNML: boolean,
  tags: Array<string>,
  isLoading: boolean,
};

class ExplorativeAnnotationsView extends React.PureComponent<Props, State> {
  state = {
    shouldShowArchivedTracings: false,
    archivedTracings: [],
    unarchivedTracings: [],
    didAlreadyFetchMetaInfo: {
      isArchived: false,
      isUnarchived: false,
    },
    searchQuery: "",
    isUploadingNML: false,
    tags: [],
    isLoading: false,
  };

  componentDidMount() {
    this.restoreSearchTags();
    this.fetchDataMaybe();
  }

  isFetchNecessary(): boolean {
    const accessor = this.state.shouldShowArchivedTracings ? "isArchived" : "isUnarchived";
    return !this.state.didAlreadyFetchMetaInfo[accessor];
  }

  restoreSearchTags() {
    // restore the search query tags from the last session
    const searchTagString = localStorage.getItem("lastDashboardSearchTags");
    if (searchTagString) {
      try {
        const searchTags = JSON.parse(searchTagString);
        this.setState({ tags: searchTags });
      } catch (error) {
        // pass
      }
    }
  }

  async fetchDataMaybe(): Promise<void> {
    if (!this.isFetchNecessary()) {
      return;
    }

    const isFinishedString = this.state.shouldShowArchivedTracings.toString();
    const url = this.props.userId
      ? `/api/users/${this.props.userId}/annotations?isFinished=${isFinishedString}`
      : `/api/user/annotations?isFinished=${isFinishedString}`;

    this.setState({ isLoading: true });
    const tracings = await Request.receiveJSON(url);
    if (this.state.shouldShowArchivedTracings) {
      this.setState(
        update(this.state, {
          isLoading: { $set: false },
          archivedTracings: { $set: tracings },
          didAlreadyFetchMetaInfo: {
            isArchived: { $set: true },
          },
        }),
      );
    } else {
      this.setState(
        update(this.state, {
          isLoading: { $set: false },
          unarchivedTracings: { $set: tracings },
          didAlreadyFetchMetaInfo: {
            isUnarchived: { $set: true },
          },
        }),
      );
    }
  }

  toggleShowArchived = () => {
    this.setState({ shouldShowArchivedTracings: !this.state.shouldShowArchivedTracings }, () => {
      this.fetchDataMaybe();
    });
  };

  finishOrReopenTracing = async (type: "finish" | "reopen", tracing: APIAnnotationType) => {
    const url =
      type === "finish"
        ? `/annotations/${tracing.typ}/${tracing.id}/finish`
        : `/annotations/${tracing.typ}/${tracing.id}/reopen`;

    const newTracing = await Request.receiveJSON(url);
    Toast.messages(newTracing.messages);

    const newTracings = this.getCurrentTracings().filter(t => t.id !== tracing.id);

    if (type === "finish") {
      this.setState({
        unarchivedTracings: newTracings,
        archivedTracings: [newTracing].concat(this.state.archivedTracings),
      });
    } else {
      this.setState({
        archivedTracings: newTracings,
        unarchivedTracings: [newTracing].concat(this.state.unarchivedTracings),
      });
    }
  };

  handleNMLUpload = (response: Object) => {
    response.messages.map(m => Toast.success(m.success));
    this.props.history.push(`/annotations/${response.annotation.typ}/${response.annotation.id}`);
  };

  renderActions = (tracing: APIAnnotationType) => {
    if (tracing.typ !== "Explorational") {
      return null;
    }

    const { typ, id } = tracing;
    if (!this.state.shouldShowArchivedTracings) {
      return (
        <div>
          <Link to={`/annotations/${typ}/${id}`}>
            <i className="fa fa-random" />
            <strong>Trace</strong>
          </Link>
          <br />
          <a href={`/annotations/${typ}/${id}/download`}>
            <i className="fa fa-download" />
            Download
          </a>
          <br />
          <AsyncLink href="#" onClick={() => this.finishOrReopenTracing("finish", tracing)}>
            <i className="fa fa-archive" />
            Archive
          </AsyncLink>
          <br />
        </div>
      );
    } else {
      return (
        <div>
          <AsyncLink href="#" onClick={() => this.finishOrReopenTracing("reopen", tracing)}>
{'fraction_non_alphanumeric': 0.13678339581238, 'fraction_numerical': 0.0003657310048459358, 'mean_word_length': 2.923242467718795, 'pattern_counts': {'":': 0, '<': 49, '<?xml version=': 0, '>': 67, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 7, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6273319', 'n_tokens_mistral': 3394, 'n_tokens_neox': 3370, 'n_words': 638}