<commit_before>import PropTypes from 'prop-types';
import React from 'react';
import createReactClass from 'create-react-class';
import Reflux from 'reflux';
import DocumentTitle from 'react-document-title';
import {withRouter} from 'react-router';

import ApiMixin from '../../mixins/apiMixin';

import MemberListStore from '../../stores/memberListStore';
import LoadingError from '../../components/loadingError';
import LoadingIndicator from '../../components/loadingIndicator';
import MissingProjectMembership from '../../components/missingProjectMembership';
import OrganizationState from '../../mixins/organizationState';
import SentryTypes from '../../proptypes';
import ProjectsStore from '../../stores/projectsStore';
import {loadEnvironments} from '../../actionCreators/environments';
import {setActiveProject} from '../../actionCreators/projects';
import {t} from '../../locale';

const ERROR_TYPES = {
  MISSING_MEMBERSHIP: 'MISSING_MEMBERSHIP',
  PROJECT_NOT_FOUND: 'PROJECT_NOT_FOUND',
  UNKNOWN: 'UNKNOWN',
};

/**
 * Higher-order component that sets `project` as a child context
 * value to be accessed by child elements.
 *
 * Additionally delays rendering of children until project XHR has finished
 * and context is populated.
 */
const ProjectContext = createReactClass({
  displayName: 'ProjectContext',

  propTypes: {
    projectId: PropTypes.string,
    orgId: PropTypes.string,
    location: PropTypes.object,
  },

  childContextTypes: {
    project: SentryTypes.Project,
  },

  mixins: [
    ApiMixin,
    Reflux.connect(MemberListStore, 'memberList'),
    Reflux.listenTo(ProjectsStore, 'onProjectChange'),
    OrganizationState,
  ],

  getInitialState() {
    return {
      loading: true,
      error: false,
      errorType: null,
      memberList: [],
      project: null,
      projectNavSection: null,
    };
  },

  getChildContext() {
    return {
      project: this.state.project,
    };
  },

  componentWillMount() {
    this.fetchData();
  },

  componentWillReceiveProps(nextProps) {
    if (nextProps.projectId !== this.props.projectId) {
      this.remountComponent();
    }
  },

  componentDidUpdate(prevProps, prevState) {
    if (prevProps.projectId !== this.props.projectId) {
      this.fetchData();
    }

    // Call forceUpdate() on <DocumentTitle/> if either project or organization
    // state has changed. This is because <DocumentTitle/>'s shouldComponentUpdate()
    // returns false unless props differ; meaning context changes for project/org
    // do NOT trigger renders for <DocumentTitle/> OR any subchildren. The end result
    // being that child elements that listen for context changes on project/org will
    // NOT update (without this hack).
    // See: https://github.com/gaearon/react-document-title/issues/35

    // intentionally shallow comparing references
    if (
      prevState.project !== this.state.project ||
      prevState.organization !== this.state.organization
    ) {
      let docTitle = this.refs.docTitle;
      if (docTitle) docTitle.forceUpdate();
    }
  },

  remountComponent() {
    this.setState(this.getInitialState());
  },

  getTitle() {
    if (this.state.project) return this.state.project.name;
    return 'Sentry';
  },

  onProjectChange(projectIds) {
    if (!this.state.project) return;
    if (!projectIds.has(this.state.project.id)) return;

    this.setState({
      project: {...ProjectsStore.getById(this.state.project.id)},
    });
  },

  identifyProject() {
    let {projectId} = this.props;
    let projectSlug = projectId;
    let activeProject = null;
    let org = this.context.organization;
    org.projects.forEach(project => {
      if (project.slug == projectSlug) {
        activeProject = project;
      }
    });
    return activeProject;
  },

  fetchData() {
    let {orgId, projectId, location} = this.props;
    // we fetch core access/information from the global organization data
    let activeProject = this.identifyProject();
    let hasAccess = activeProject && activeProject.hasAccess;

    this.setState({
      loading: true,
      // we bind project initially, but it'll rebind
      project: activeProject,
    });

    if (activeProject && hasAccess) {
      setActiveProject(null);
      const projectRequest = this.api.requestPromise(`/projects/${orgId}/${projectId}/`);

      const environmentRequest = this.api.requestPromise(
        this.getEnvironmentListEndpoint()
      );

      Promise.all([projectRequest, environmentRequest]).then(
        ([project, envs]) => {
          this.setState({
            loading: false,
            project,
            error: false,
            errorType: null,
          });

          // assuming here that this means the project is considered the active project
          setActiveProject(project);

          // If an environment is specified in the query string, load it instead of default
          const queryEnv = location.query.environment;
          const envName =
            typeof queryEnv === 'undefined' ? project.defaultEnvironment : queryEnv;

          loadEnvironments(envs, envName);
        },
        () => {
          this.setState({
            loading: false,
            error: false,
            errorType: ERROR_TYPES.UNKNOWN,
          });
        }
      );

      // TODO(dcramer): move member list to organization level
      this.api.request(this.getMemberListEndpoint(), {
        success: data => {
          MemberListStore.loadInitialData(data.filter(m => m.user).map(m => m.user));
        },
      });
    } else if (activeProject && !activeProject.isMember) {
      this.setState({
        loading: false,
        error: true,
        errorType: ERROR_TYPES.MISSING_MEMBERSHIP,
      });
    } else {
      this.setState({
        loading: false,
        error: true,<commit_msg>fix(environments): Prevent default environment from being "" (no environment) (#7732)<commit_after>import PropTypes from 'prop-types';
import React from 'react';
import createReactClass from 'create-react-class';
import Reflux from 'reflux';
import DocumentTitle from 'react-document-title';
import {withRouter} from 'react-router';

import ApiMixin from '../../mixins/apiMixin';

import MemberListStore from '../../stores/memberListStore';
import LoadingError from '../../components/loadingError';
import LoadingIndicator from '../../components/loadingIndicator';
import MissingProjectMembership from '../../components/missingProjectMembership';
import OrganizationState from '../../mixins/organizationState';
import SentryTypes from '../../proptypes';
import ProjectsStore from '../../stores/projectsStore';
import {loadEnvironments} from '../../actionCreators/environments';
import {setActiveProject} from '../../actionCreators/projects';
import {t} from '../../locale';

const ERROR_TYPES = {
  MISSING_MEMBERSHIP: 'MISSING_MEMBERSHIP',
  PROJECT_NOT_FOUND: 'PROJECT_NOT_FOUND',
  UNKNOWN: 'UNKNOWN',
};

/**
 * Higher-order component that sets `project` as a child context
 * value to be accessed by child elements.
 *
 * Additionally delays rendering of children until project XHR has finished
 * and context is populated.
 */
const ProjectContext = createReactClass({
  displayName: 'ProjectContext',

  propTypes: {
    projectId: PropTypes.string,
    orgId: PropTypes.string,
    location: PropTypes.object,
  },

  childContextTypes: {
    project: SentryTypes.Project,
  },

  mixins: [
    ApiMixin,
    Reflux.connect(MemberListStore, 'memberList'),
    Reflux.listenTo(ProjectsStore, 'onProjectChange'),
    OrganizationState,
  ],

  getInitialState() {
    return {
      loading: true,
      error: false,
      errorType: null,
      memberList: [],
      project: null,
      projectNavSection: null,
    };
  },

  getChildContext() {
    return {
      project: this.state.project,
    };
  },

  componentWillMount() {
    this.fetchData();
  },

  componentWillReceiveProps(nextProps) {
    if (nextProps.projectId !== this.props.projectId) {
      this.remountComponent();
    }
  },

  componentDidUpdate(prevProps, prevState) {
    if (prevProps.projectId !== this.props.projectId) {
      this.fetchData();
    }

    // Call forceUpdate() on <DocumentTitle/> if either project or organization
    // state has changed. This is because <DocumentTitle/>'s shouldComponentUpdate()
    // returns false unless props differ; meaning context changes for project/org
    // do NOT trigger renders for <DocumentTitle/> OR any subchildren. The end result
    // being that child elements that listen for context changes on project/org will
    // NOT update (without this hack).
    // See: https://github.com/gaearon/react-document-title/issues/35

    // intentionally shallow comparing references
    if (
      prevState.project !== this.state.project ||
      prevState.organization !== this.state.organization
    ) {
      let docTitle = this.refs.docTitle;
      if (docTitle) docTitle.forceUpdate();
    }
  },

  remountComponent() {
    this.setState(this.getInitialState());
  },

  getTitle() {
    if (this.state.project) return this.state.project.name;
    return 'Sentry';
  },

  onProjectChange(projectIds) {
    if (!this.state.project) return;
    if (!projectIds.has(this.state.project.id)) return;

    this.setState({
      project: {...ProjectsStore.getById(this.state.project.id)},
    });
  },

  identifyProject() {
    let {projectId} = this.props;
    let projectSlug = projectId;
    let activeProject = null;
    let org = this.context.organization;
    org.projects.forEach(project => {
      if (project.slug == projectSlug) {
        activeProject = project;
      }
    });
    return activeProject;
  },

  fetchData() {
    let {orgId, projectId, location} = this.props;
    // we fetch core access/information from the global organization data
    let activeProject = this.identifyProject();
    let hasAccess = activeProject && activeProject.hasAccess;

    this.setState({
      loading: true,
      // we bind project initially, but it'll rebind
      project: activeProject,
    });

    if (activeProject && hasAccess) {
      setActiveProject(null);
      const projectRequest = this.api.requestPromise(`/projects/${orgId}/${projectId}/`);

      const environmentRequest = this.api.requestPromise(
        this.getEnvironmentListEndpoint()
      );

      Promise.all([projectRequest, environmentRequest]).then(
        ([project, envs]) => {
          this.setState({
            loading: false,
            project,
            error: false,
            errorType: null,
          });

          // assuming here that this means the project is considered the active project
          setActiveProject(project);

          // If an environment is specified in the query string, load it instead of default
          const queryEnv = location.query.environment;
          // The default environment cannot be "" (No Environment)
          const defaultEnv = project.defaultEnv || null;
          const envName = typeof queryEnv === 'undefined' ? defaultEnv : queryEnv;
          loadEnvironments(envs, envName);
        },
        () => {
          this.setState({
            loading: false,
            error: false,
            errorType: ERROR_TYPES.UNKNOWN,
          });
        }
      );

      // TODO(dcramer): move member list to organization level
      this.api.request(this.getMemberListEndpoint(), {
        success: data => {
          MemberListStore.loadInitialData(data.filter(m => m.user).map(m => m.user));
        },
      });
    } else if (activeProject && !activeProject.isMember) {
      this.setState({
        loading: false,
        error: true,
        errorType: ERROR_TYPES.MISSING_MEMBERSHIP,
      });
    } else {
      this.setState({
        loading: false,
        error: true,
{'fraction_non_alphanumeric': 0.1209396997710118, 'fraction_numerical': 0.0006784835891781867, 'mean_word_length': 2.813712807244502, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 21, 'https://': 2, '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': '2275250', 'n_tokens_mistral': 3266, 'n_tokens_neox': 3231, 'n_words': 827}