<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import { autobind } from 'core-decorators';
import { connect } from 'react-redux';
import { Alert, Icon, Tabs } from 'antd';
import history from '../../common/history';
import { CodeView } from './';

const TabPane = Tabs.TabPane;
export class RoutesPage extends Component {
  static propTypes = {
    match: PropTypes.object.isRequired,
    home: PropTypes.object.isRequired,
  };

  @autobind
  handleTabChange(tabKey) {
    const fid = this.props.match.params.feature;
    switch (tabKey) {
      case 'rules':
        history.push(`/${fid}/routes`);
        break;
      case 'code':
        history.push(`/${fid}/routes/code`);
        break;
      default:
        break;
    }
  }

  renderNotFound(fid) {
    return (
      <div className="home-routes-page">
        <span style={{ color: 'red' }}>Feature not found: {fid}.</span>
      </div>
    );
  }

  render() {
    const params = this.props.match.params;
    const fid = params.feature;
    let tabKey = params.type;
    if (tabKey !== 'code') tabKey = 'rules';
    const feature = this.props.home.featureById[fid];
    if (!feature) {
      return this.renderNotFound(fid);
    }
    const routes = feature.routes;
    const devPort = this.props.home.rekit.devPort;

    const codeFile = `src/features/${fid}/route.js`;
    return (
      <div className="home-routes-page">
        <h2><Icon type="share-alt" /> &nbsp;{fid} / routes</h2>
        <Tabs activeKey={tabKey} animated={false} onChange={this.handleTabChange}>
          <TabPane tab="Rules" key="rules">
            <p>This is a rough overview of routing config defined in a feature. </p>
            <p>If a route rule isIndex === true and also has a path property then there will be two rules.</p>
            <p>For more detailed information, please look into the <Link to={`/${fid}/routes/code`}>code</Link>.</p>
            <p>NOTE: if route path has parameters, you need to alter the link address with correct values after click the route link. </p>
            {routes.length === 0
              ? <Alert type="info" message="No routing rules defined." showIcon />
              :
              <table>
                <thead>
                  <tr>
                    <th>Path</th>
                    <th>Component</th>
                  </tr>
                </thead>
                <tbody>
                  {routes.map(route => (
                    <tr key={route.path}>
                      <td><a href={`//localhost:${devPort}${route.path}`} target="_blank">{route.path}</a></td>
                      <td>{fid}/{route.component}</td>
                    </tr>
                  ))}
                </tbody>
              </table>}
          </TabPane>
          <TabPane tab="Code" key="code">
            <CodeView file={codeFile} />
          </TabPane>
        </Tabs>
      </div>
    );
  }
}
<commit_msg>Routes page support code editor.<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import { autobind } from 'core-decorators';
import { connect } from 'react-redux';
import { Alert, Icon, Tabs } from 'antd';
import history from '../../common/history';
import { CodeEditor } from './';

const TabPane = Tabs.TabPane;
export class RoutesPage extends Component {
  static propTypes = {
    match: PropTypes.object.isRequired,
    home: PropTypes.object.isRequired,
  };

  state = {
    codeChanged: false,
  };

  @autobind
  handleTabChange(tabKey) {
    const fid = this.props.match.params.feature;
    switch (tabKey) {
      case 'rules':
        history.push(`/${fid}/routes`);
        break;
      case 'code':
        history.push(`/${fid}/routes/code`);
        break;
      default:
        break;
    }
  }

  handleCodeChange = (args) => {
    this.setState({
      codeChanged: args.hasChange,
    });
  }

  renderNotFound(fid) {
    return (
      <div className="home-routes-page">
        <span style={{ color: 'red' }}>Feature not found: {fid}.</span>
      </div>
    );
  }

  render() {
    const params = this.props.match.params;
    const fid = params.feature;
    let tabKey = params.type;
    if (tabKey !== 'code') tabKey = 'rules';
    const feature = this.props.home.featureById[fid];
    if (!feature) {
      return this.renderNotFound(fid);
    }
    const routes = feature.routes;
    const devPort = this.props.home.rekit.devPort;

    const codeFile = `src/features/${fid}/route.js`;
    const codeChangeMark = this.state.codeChanged ? ' *' : '';
    return (
      <div className="home-routes-page">
        <h2><Icon type="share-alt" /> &nbsp;{fid} / routes</h2>
        <Tabs activeKey={tabKey} animated={false} onChange={this.handleTabChange}>
          <TabPane tab="Rules" key="rules">
            <p>This is a rough overview of routing config defined in a feature. </p>
            <p>If a route rule isIndex === true and also has a path property then there will be two rules.</p>
            <p>For more detailed information, please look into the <Link to={`/${fid}/routes/code`}>code</Link>.</p>
            <p>NOTE: if route path has parameters, you need to alter the link address with correct values after click the route link. </p>
            {routes.length === 0
              ? <Alert type="info" message="No routing rules defined." showIcon />
              :
              <table>
                <thead>
                  <tr>
                    <th>Path</th>
                    <th>Component</th>
                  </tr>
                </thead>
                <tbody>
                  {routes.map(route => (
                    <tr key={route.path}>
                      <td><a href={`//localhost:${devPort}${route.path}`} target="_blank">{route.path}</a></td>
                      <td>{fid}/{route.component}</td>
                    </tr>
                  ))}
                </tbody>
              </table>}
          </TabPane>
          <TabPane tab={`Code${codeChangeMark}`} key="code">
            <CodeEditor file={codeFile} onStateChange={this.handleCodeChange} />
          </TabPane>
        </Tabs>
      </div>
    );
  }
}

{'fraction_non_alphanumeric': 0.14853222718570516, 'fraction_numerical': 0.0009572431397574984, 'mean_word_length': 1.969682614874467, 'pattern_counts': {'":': 0, '<': 97, '<?xml version=': 0, '>': 100, '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': '526148', 'n_tokens_mistral': 1875, 'n_tokens_neox': 1870, 'n_words': 460}