<commit_before>import * as React from "react";
import styled from "styled-components";
import { NewNotebookNavigation } from "@nteract/connected-components";
import {
  Entry,
  Listing,
  Icon,
  Name,
  LastSaved
} from "@nteract/directory-listing";
import {
  selectors,
  AppState,
  KernelspecRecord,
  KernelspecProps,
  JupyterHostRecord,
  ContentRef,
  DirectoryContentRecord
} from "@nteract/core";
import { connect } from "react-redux";

import { Nav, NavSection } from "../components/nav";
import { openNotebook } from "../triggers/open-notebook";
import { ThemedLogo } from "../components/themed-logo";

import urljoin from "url-join";

const ListingRoot = styled.div`
  margin-top: 2rem;
  padding-left: 2rem;
  padding-right: 2rem;
`;

type LightDirectoryEntry = {
  last_modified: Date | null;
  name: string;
  path: string;
  type: "notebook" | "dummy" | "directory" | "file" | "unknown";
};

type LightDirectoryEntries = LightDirectoryEntry[];

type DirectoryProps = {
  appBase: string;
  content: DirectoryContentRecord;
  host: JupyterHostRecord;
  appVersion: string;
  contentRef: ContentRef;
  contents: LightDirectoryEntries;
};

export class DirectoryApp extends React.PureComponent<DirectoryProps> {
  openNotebook = (ks: KernelspecRecord | KernelspecProps) => {
    openNotebook(this.props.host, ks, {
      appBase: this.props.appBase,
      appVersion: this.props.appVersion,
      // Since we're looking at a directory, the base dir is the directory we are in
      baseDir: this.props.content.filepath
    });
  };

  render() {
    const atRoot = this.props.content.filepath === "/";

    const dotdothref = urljoin(
      this.props.appBase,
      // Make sure leading / and .. don't navigate outside of the appBase
      urljoin(this.props.content.filepath, "..")
    );
    const dotdotlink = (
      <a href={dotdothref} title="Navigate down a directory" role="button">
        {".."}
      </a>
    );
    return (
      <React.Fragment>
        <Nav contentRef={this.props.contentRef}>
          <NavSection>
            <a href={urljoin(this.props.appBase)} title="Home" role="button">
              <ThemedLogo />
            </a>
            <span>{this.props.content.filepath.split("/").pop()}</span>
          </NavSection>
        </Nav>
        <NewNotebookNavigation onClick={this.openNotebook} />
        <ListingRoot>
          <Listing>
            {atRoot ? null : (
              // TODO: Create a contentRef for `..`, even though it's a placeholder
              // When we're not at the root of the tree, show `..`
              <Entry>
                <Icon fileType={"directory"} />
                <Name>{dotdotlink}</Name>
              </Entry>
            )}
            {this.props.contents.map((entry, index) => {
              const link = (
                <a
                  href={urljoin(this.props.appBase, entry.path)}
                  // When it's a notebook, we open a new tab
                  target={entry.type === "notebook" ? "_blank" : undefined}
                >
                  {entry.name}
                </a>
              );
              return (
                <Entry key={index}>
                  <Icon fileType={entry.type} />
                  <Name>{link}</Name>
                  <LastSaved lastModified={entry.last_modified} />
                </Entry>
              );
            })}
          </Listing>
        </ListingRoot>
      </React.Fragment>
    );
  }
}

const mapStateToDirectoryProps = (
  state: AppState,
  ownProps: { contentRef: ContentRef; appBase: string }
): DirectoryProps => {
  const { contentRef, appBase } = ownProps;

  const host = selectors.currentHost(state);
  const content = selectors.content(state, ownProps);

  if (host.type !== "jupyter") {
    throw new Error("This component only works with jupyter servers");
  }

  if (!content || content.type !== "directory") {
    throw new Error(
      "The directory component should only be used with directory contents"
    );
  }

  const contents: LightDirectoryEntry[] = [];
  content.model.items.map((entryRef: string) => {
    const row = selectors.content(state, { contentRef: entryRef });
    if (!row) {
      return {
        last_modified: new Date(),
        name: "",
        path: "",
        type: ""
      };
    }

    if (row.type !== "dummy") {
      return null;
    }

    contents.push({
      last_modified: row.lastSaved,
      name: row.filepath,
      path: row.filepath,
      type: row.assumedType
    });
  });

  return {
    appBase,
    appVersion: selectors.appVersion(state),
    content,
    contentRef,<commit_msg>changing type<commit_after>import * as React from "react";
import styled from "styled-components";
import { NewNotebookNavigation } from "@nteract/connected-components";
import {
  Entry,
  Listing,
  Icon,
  Name,
  LastSaved
} from "@nteract/directory-listing";
import {
  selectors,
  AppState,
  KernelspecRecord,
  KernelspecProps,
  JupyterHostRecord,
  ContentRef,
  DirectoryContentRecord
} from "@nteract/core";
import { connect } from "react-redux";

import { Nav, NavSection } from "../components/nav";
import { openNotebook } from "../triggers/open-notebook";
import { ThemedLogo } from "../components/themed-logo";

import urljoin from "url-join";

const ListingRoot = styled.div`
  margin-top: 2rem;
  padding-left: 2rem;
  padding-right: 2rem;
`;

type LightDirectoryEntry = {
  last_modified: Date | null;
  name: string;
  path: string;
  type: "notebook" | "dummy" | "directory" | "file" | "unknown";
};

type LightDirectoryEntries = LightDirectoryEntry[];

type DirectoryProps = {
  appBase: string;
  content: DirectoryContentRecord;
  host: JupyterHostRecord;
  appVersion: string;
  contentRef: ContentRef;
  contents: LightDirectoryEntries;
};

export class DirectoryApp extends React.PureComponent<DirectoryProps> {
  openNotebook = (ks: KernelspecRecord | KernelspecProps) => {
    openNotebook(this.props.host, ks, {
      appBase: this.props.appBase,
      appVersion: this.props.appVersion,
      // Since we're looking at a directory, the base dir is the directory we are in
      baseDir: this.props.content.filepath
    });
  };

  render() {
    const atRoot = this.props.content.filepath === "/";

    const dotdothref = urljoin(
      this.props.appBase,
      // Make sure leading / and .. don't navigate outside of the appBase
      urljoin(this.props.content.filepath, "..")
    );
    const dotdotlink = (
      <a href={dotdothref} title="Navigate down a directory" role="button">
        {".."}
      </a>
    );
    return (
      <React.Fragment>
        <Nav contentRef={this.props.contentRef}>
          <NavSection>
            <a href={urljoin(this.props.appBase)} title="Home" role="button">
              <ThemedLogo />
            </a>
            <span>{this.props.content.filepath.split("/").pop()}</span>
          </NavSection>
        </Nav>
        <NewNotebookNavigation onClick={this.openNotebook} />
        <ListingRoot>
          <Listing>
            {atRoot ? null : (
              // TODO: Create a contentRef for `..`, even though it's a placeholder
              // When we're not at the root of the tree, show `..`
              <Entry>
                <Icon fileType={"directory"} />
                <Name>{dotdotlink}</Name>
              </Entry>
            )}
            {this.props.contents.map((entry, index) => {
              const link = (
                <a
                  href={urljoin(this.props.appBase, entry.path)}
                  // When it's a notebook, we open a new tab
                  target={entry.type === "notebook" ? "_blank" : undefined}
                >
                  {entry.name}
                </a>
              );
              return (
                <Entry key={index}>
                  <Icon fileType={entry.type} />
                  <Name>{link}</Name>
                  <LastSaved lastModified={entry.last_modified} />
                </Entry>
              );
            })}
          </Listing>
        </ListingRoot>
      </React.Fragment>
    );
  }
}

const mapStateToDirectoryProps = (
  state: AppState,
  ownProps: { contentRef: ContentRef; appBase: string }
): DirectoryProps => {
  const { contentRef, appBase } = ownProps;

  const host = selectors.currentHost(state);
  const content = selectors.content(state, ownProps);

  if (host.type !== "jupyter") {
    throw new Error("This component only works with jupyter servers");
  }

  if (!content || content.type !== "directory") {
    throw new Error(
      "The directory component should only be used with directory contents"
    );
  }

  const contents: LightDirectoryEntry[] = [];
  content.model.items.map((entryRef: ContentRef) => {
    const row = selectors.content(state, { contentRef: entryRef });
    if (!row) {
      return {
        last_modified: new Date(),
        name: "",
        path: "",
        type: ""
      };
    }

    if (row.type !== "dummy") {
      return null;
    }

    contents.push({
      last_modified: row.lastSaved,
      name: row.filepath,
      path: row.filepath,
      type: row.assumedType
    });
  });

  return {
    appBase,
    appVersion: selectors.appVersion(state),
    content,
    contentRef,
{'fraction_non_alphanumeric': 0.13147668393782383, 'fraction_numerical': 0.0006476683937823834, 'mean_word_length': 2.2147814018043026, 'pattern_counts': {'":': 0, '<': 67, '<?xml version=': 0, '>': 75, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, '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': '7061965', 'n_tokens_mistral': 2803, 'n_tokens_neox': 2730, 'n_words': 644}