<|start_filename|>app/renderer/actions/index.js<|end_filename|>
import * as configActions from './Config';
import * as serverMonitorActions from './ServerMonitor';
import * as startServerActions from './StartServer';
import * as updaterActions from '../../../gui-common/actions/Updater';

export default {
  ...configActions,
  ...serverMonitorActions,
  ...startServerActions,
  ...updaterActions,
};


<|start_filename|>app/renderer/components/StartServer/AdvancedTab.js<|end_filename|>
import React, { Component } from 'react';
import {Modal, Input, Checkbox, notification, Tooltip} from 'antd';

import { withTranslation } from '../../util';
import { propTypes, updateArg } from './shared';
import StartButton from './StartButton';
import SavePresetButton from './SavePresetButton';
import styles from './AdvancedTab.css';
import { INPUT } from '../../../../gui-common/components/AntdTypes';

// args we build a UI for:
// ipa, address, port, callbackAddress, callbackPort,
// bootstrapPort, backendRetries, sessionOverride, log,
// logLevel, logTimestamp, localTimezone, logNoColors,
// defaultDevice, automationTraceTemplatePath, instrumentsPath,
// nodeconfig, robotAddress, robotPort, selendroidPort,
// chromeDriverPort, chromedriverExecutable, enforceStrictCaps,
// isolateSimDevice, tmpDir, traceDir, debugLogSpacing, allowCors,
// suppressAdbKillServer, webkitDebugProxyPort, defaultCapabilities

class AdvancedTab extends Component {

  constructor (props) {
    super(props);
    this.state = {
      modalOpen: false,
      newPresetName: '',
    };
  }

  buildInput (argName, type, label) {
    const {serverArgs, t} = this.props;

    if (type === 'text') {
      return (
        <div className={styles.input}>
          <Input ref={argName} type={INPUT.TEXT}
            defaultValue={serverArgs[argName]}
            name={argName} onChange={updateArg.bind(this)}
            addonBefore={label}
          />
        </div>
      );
    }

    if (type === 'checkbox') {
      return (
        <div className={styles.input}>
          <Checkbox ref={argName}
            name={argName} defaultChecked={serverArgs[argName]}
            onChange={updateArg.bind(this)}
          >{label}</Checkbox>
        </div>
      );
    }

    if (type === 'textarea') {
      return '';
    }

    throw new Error(t('invalidType', {type}));
  }

  openPresetModal () {
    this.setState({
      modalOpen: true,
    });
  }

  closePresetModal () {
    this.setState({modalOpen: false});
  }

  updatePresetName (evt) {
    this.setState({newPresetName: evt.target.value});
  }

  savePreset (evt) {
    const {t} = this.props;
    if (evt) {
      // might get here from Modal binding (no event) or form submit binding
      // (event)
      evt.preventDefault();
    }
    if (!this.state.newPresetName) {
      // don't save a preset without a name
      return;
    }
    this.props.savePreset(this.state.newPresetName, this.props.serverArgs);
    notification.success({
      message: t('Saved'),
      description: t('presetAdded', {presetName: this.state.newPresetName})
    });
    this.setState({modalOpen: false});
  }

  modal () {
    const {t} = this.props;
    const form = (
      <div>
        <form className={styles.input}
          onSubmit={this.savePreset.bind(this)}>
          <Input autoFocus
            ref="presetName"
            name={'presetName'}
            addonBefore={t('Preset name')}
            onChange={this.updatePresetName.bind(this)}
            size="large"
          />
          <input type={INPUT.SUBMIT} hidden={true} />
        </form>
      </div>
    );

    return (
      <Modal
        visible={this.state.modalOpen}
        className={styles.presetModal}
        title={t('Save Server Arguments Preset')}
        width={340}
        okText={t('Save')}
        onOk={this.savePreset.bind(this)}
        cancelText={t('Cancel')}
        onCancel={this.closePresetModal.bind(this)}
      >
        {form}
      </Modal>
    );
  }

  render () {
    const {startServer, serverStarting, presetSaving, serverVersion, t} = this.props;

    return (
      <div className={styles.advancedForm}>
        <form onSubmit={startServer}>
          <div className={styles.inputSection}>
            <div className={styles.secTitle}>{t('General')}</div>
            <div className={styles.secBody}>
              {this.buildInput('address', 'text', t('Server Address'))}
              {this.buildInput('port', 'text', t('Server Port'))}
              {this.buildInput('log', 'text', t('Logfile Path'))}
              {this.buildInput('loglevel', 'text', t('Log Level'))}
              {this.buildInput('tmpDir', 'text', t('Override Temp Path'))}
              {this.buildInput('nodeconfig', 'text', t('Node Config File Path'))}
              {this.buildInput('localTimezone', 'checkbox', t('Local Timezone'))}
              {this.buildInput('sessionOverride', 'checkbox', t('Allow Session Override'))}
              {this.buildInput('logTimestamp', 'checkbox', t('Log Timestamps'))}
              {this.buildInput('logNoColors', 'checkbox', t('Suppress Log Color'))}
              {this.buildInput('enforceStrictCaps', 'checkbox', t('Strict Caps Mode'))}
              <Tooltip title={t('relaxedSecurityInfo')}>
                {this.buildInput('relaxedSecurityEnabled', 'checkbox', t('Relaxed Security'))}
              </Tooltip>
              {this.buildInput('allowCors', 'checkbox', t('Allow CORS'))}
              {this.buildInput('defaultCapabilities', 'textarea', t('Default Capabilities'))}
            </div>

            <div className={styles.secTitle}>{t('iOS')}</div>
            <div className={styles.secBody}>
              {this.buildInput('wdaLocalPort', 'text', t('WebDriverAgent Port'))}
              {this.buildInput('callbackHost', 'text', t('executeAsync Callback Host'))}
              {this.buildInput('callbackPort', 'text', t('executeAsync Callback Port'))}
            </div>

            <div className={styles.secTitle}>{t('Android')}</div>
            <div className={styles.secBody}>
              {this.buildInput('bootstrapPort', 'text', t('Bootstrap Port'))}
              {this.buildInput('selendroidPort', 'text', t('Selendroid Port'))}
              {this.buildInput('chromeDriverPort', 'text', t('Chromedriver Port'))}
              {this.buildInput('chromedriverExecutable', 'text', t('Chromedriver Binary Path'))}
            </div>
          </div>
          <div className={styles.actions}>
            <StartButton {...{serverStarting, startServer, serverVersion}} />
            <SavePresetButton {...{savePreset: this.openPresetModal.bind(this), presetSaving}} />
          </div>
        </form>
        {this.modal()}
      </div>
    );
  }
}

AdvancedTab.propTypes = {...propTypes};

export default withTranslation(AdvancedTab);


<|start_filename|>app/shared/settings.js<|end_filename|>
import settings from 'electron-settings';

export const PRESETS = 'presets';
export const SERVER_ARGS = 'SERVER_ARGS';
export const PREFERRED_LANGUAGE = 'PREFERRED_LANGUAGE';

// set default persistent settings
// do it here because settings are kind of like state!
settings.defaults({
  [PRESETS]: {},
  [SERVER_ARGS]: null,
  [PREFERRED_LANGUAGE]: 'en',
});

export default settings;


<|start_filename|>app/configs/i18next.config.renderer.js<|end_filename|>
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import config from './app.config';
import settings from '../shared/settings';
import i18nextBackend from 'i18next-node-fs-backend';
import { getI18NextOptions } from '../../gui-common/configs/app.config.default';

const i18nextOptions = getI18NextOptions(settings, config);

if (!i18n.isInitialized) {
  i18n
    .use(initReactI18next)
    .use(i18nextBackend)
    .init(i18nextOptions);
}

export default i18n;


<|start_filename|>app/renderer/components/StartServer/StartButton.js<|end_filename|>
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Button } from 'antd';
import { ipcRenderer } from 'electron';
import { withTranslation } from '../../util';
import { SettingOutlined } from '@ant-design/icons';

import styles from './StartButton.css';
import { BUTTON, INPUT } from '../../../../gui-common/components/AntdTypes';

class StartButton extends Component {
  isEnabled () {
    return !(this.props.serverStarting || this.props.disabledOverride);
  }

  noop (evt) {
    evt.preventDefault();
  }

  openConfig () {
    ipcRenderer.send('appium-open-config');
  }

  render () {
    const {startServer, serverStarting, serverVersion, t} = this.props;
    const buttonProps = {};
    if (!this.isEnabled()) {
      buttonProps.disabled = true;
    }

    return (
      <div>
        <Button {...buttonProps} id='startServerBtn'
          className={styles.startButton}
          type={BUTTON.PRIMARY}
          onClick={this.isEnabled() ? startServer : this.noop}
        >
          {serverStarting ? t('Starting…') : t('startServer', {serverVersion})}
        </Button>
        <input type={INPUT.SUBMIT} hidden={true} />
        <Button id='configBtn'
          className={styles.configButton}
          onClick={() => this.openConfig()}>
          {t('Edit Configurations')}<SettingOutlined />
        </Button>
      </div>
    );
  }
}

StartButton.propTypes = {
  serverStarting: PropTypes.bool.isRequired,
  startServer: PropTypes.func.isRequired,
  disabledOverride: PropTypes.bool,
};

export default withTranslation(StartButton);


<|start_filename|>app/main/menus.js<|end_filename|>
import { app, shell, dialog, Menu } from 'electron';
import { createNewConfigWindow} from './appium';
import { checkNewUpdates } from './auto-updater';
import config from '../configs/app.config';
import i18n from '../configs/i18next.config';
import { rebuildMenus as _rebuildMenus } from '../../gui-common/menus';

export function rebuildMenus (mainWindow) {
  const extraMacMenus = [{
    index: 0,
    menu: {
      label: i18n.t('Configurations…'),
      click () {
        createNewConfigWindow(mainWindow);
      }
    },
  }];

  _rebuildMenus({mainWindow, config, Menu, dialog, i18n, app, checkNewUpdates, extraMacMenus, shell});
}


<|start_filename|>test/e2e/pre-e2e.test.js<|end_filename|>
import { Application } from 'spectron';
import { fs, logger } from 'appium-support';
import chai from 'chai';
import chaiAsPromised from 'chai-as-promised';
import { e2eBefore, e2eAfter } from '../../gui-common/test-helpers';

const log = logger.getLogger('E2E Test');

chai.should();
chai.use(chaiAsPromised);

before(e2eBefore({appName: 'server', log, Application, fs}));
after(e2eAfter);


<|start_filename|>app/renderer/util.js<|end_filename|>
import { withTranslation as wt } from 'react-i18next';
import _ from 'lodash';
import config from '../configs/app.config';

export function withTranslation (componentCls, ...hocs) {
  return _.flow(
    ...hocs,
    wt(config.namespace),
  )(componentCls);
}
