Browse Source

ui: various improvements and tests

- expand test suite to cover additional form components
- fix various cases of not propagating context in es6 classes
David Cramer 7 years ago
parent
commit
a0c4eaa93b

+ 2 - 2
src/sentry/static/sentry/app/components/bases/pluginComponentBase.jsx

@@ -16,8 +16,8 @@ const callbackWithArgs = function(callback, ...args) {
 };
 
 class PluginComponentBase extends React.Component {
-  constructor(props) {
-    super(props);
+  constructor(props, context) {
+    super(props, context);
 
     [
       'onLoadSuccess',

+ 2 - 2
src/sentry/static/sentry/app/components/forms/apiForm.jsx

@@ -14,8 +14,8 @@ export default class ApiForm extends Form {
     apiEndpoint: React.PropTypes.string.isRequired
   };
 
-  constructor(props) {
-    super(props);
+  constructor(props, context) {
+    super(props, context);
     this.api = new Client();
   }
 

+ 2 - 2
src/sentry/static/sentry/app/components/forms/form.jsx

@@ -27,8 +27,8 @@ export default class Form extends React.Component {
     form: React.PropTypes.object.isRequired
   };
 
-  constructor(props) {
-    super(props);
+  constructor(props, context) {
+    super(props, context);
     this.state = {
       data: {...this.props.initialData},
       errors: {},

+ 1 - 0
src/sentry/static/sentry/app/components/forms/multipleCheckboxField.jsx

@@ -5,6 +5,7 @@ import FormField from './formField';
 
 export default class MultipleCheckboxField extends FormField {
   static propTypes = {
+    ...FormField.propTypes,
     choices: React.PropTypes.array.isRequired
   };
 

+ 11 - 0
src/sentry/static/sentry/app/components/forms/numberField.jsx

@@ -1,6 +1,17 @@
+import React from 'react';
 import InputField from './inputField';
 
 export default class NumberField extends InputField {
+  static propTypes = {
+    ...InputField.propTypes,
+    min: React.PropTypes.number,
+    max: React.PropTypes.number
+  };
+
+  coerceValue(value) {
+    return parseInt(value, 10);
+  }
+
   getType() {
     return 'number';
   }

+ 41 - 36
src/sentry/static/sentry/app/components/forms/passwordField.jsx

@@ -1,37 +1,33 @@
 import React from 'react';
 import InputField from './inputField';
-import {FormState} from '.';
+import {FormState} from './state';
 
-class PasswordField extends InputField {
-  constructor(props) {
-    super(props);
+// TODO(dcramer): im not entirely sure this is working correctly with
+// value propagation in all scenarios
+export default class PasswordField extends InputField {
+  static propTypes = {
+    ...InputField.propTypes,
+    hasSavedValue: React.PropTypes.bool,
+    prefix: React.PropTypes.string
+  };
 
-    this.startEdit = this.startEdit.bind(this);
-    this.cancelEdit = this.cancelEdit.bind(this);
+  static defaultProps = {
+    ...InputField.defaultProps,
+    hasSavedValue: false,
+    prefix: ''
+  };
 
-    this.state.editing = false;
-  }
-
-  getType() {
-    return 'password';
-  }
+  constructor(props, context) {
+    super(props, context);
 
-  cancelEdit(ev) {
-    ev.preventDefault();
-    this.setState(
-      {
-        value: '',
-        editing: false
-      },
-      () => {
-        this.props.onChange('');
-      }
-    );
+    this.state.editing = false;
   }
 
   componentWillReceiveProps(nextProps) {
     // close edit mode after successful save
+    // TODO(dcramer): this needs to work with this.context.form
     if (
+      this.props.formState &&
       this.props.formState === FormState.SAVING &&
       nextProps.formState === FormState.READY
     ) {
@@ -41,15 +37,31 @@ class PasswordField extends InputField {
     }
   }
 
-  startEdit(ev) {
-    ev.preventDefault();
+  getType() {
+    return 'password';
+  }
+
+  cancelEdit = e => {
+    e.preventDefault();
+    this.setState(
+      {
+        editing: false
+      },
+      () => {
+        this.setValue('');
+      }
+    );
+  };
+
+  startEdit = e => {
+    e.preventDefault();
     this.setState({
       editing: true
     });
-  }
+  };
 
   getField() {
-    if (!this.props.has_saved_value) {
+    if (!this.props.hasSavedValue) {
       return super.getField();
     }
 
@@ -60,7 +72,7 @@ class PasswordField extends InputField {
             {super.getField()}
           </div>
           <div>
-            <a href="#" onClick={this.cancelEdit}>Cancel</a>
+            <a onClick={this.cancelEdit}>Cancel</a>
           </div>
         </div>
       );
@@ -70,16 +82,9 @@ class PasswordField extends InputField {
           <span>
             {this.props.prefix + new Array(21 - this.props.prefix.length).join('*')}
           </span>
-          {!this.props.disabled && <a href="#" onClick={this.startEdit}>Edit</a>}
+          {!this.props.disabled && <a onClick={this.startEdit}>Edit</a>}
         </div>
       );
     }
   }
 }
-
-PasswordField.defaultProps = Object.assign({}, InputField.defaultProps, {
-  has_saved_value: false,
-  prefix: ''
-});
-
-export default PasswordField;

+ 26 - 15
src/sentry/static/sentry/app/components/forms/rangeField.jsx

@@ -1,9 +1,35 @@
+import React from 'react';
 import jQuery from 'jquery';
 import ReactDOM from 'react-dom';
 
 import InputField from './inputField';
 
 export default class RangeField extends InputField {
+  static formatMinutes = value => {
+    value = value / 60;
+    return `${value} minute${value != 1 ? 's' : ''}`;
+  };
+
+  static propTypes = {
+    ...InputField.propTypes,
+    min: React.PropTypes.number,
+    max: React.PropTypes.number,
+    step: React.PropTypes.number,
+    snap: React.PropTypes.bool,
+    allowedValues: React.PropTypes.arrayOf(React.PropTypes.number)
+  };
+
+  static defaultProps = {
+    ...InputField.defaultProps,
+    onChange: value => {},
+    formatLabel: value => value,
+    min: 0,
+    max: 100,
+    step: 1,
+    snap: true,
+    allowedValues: null
+  };
+
   componentDidMount() {
     super.componentDidMount();
     this.attachSlider();
@@ -58,18 +84,3 @@ export default class RangeField extends InputField {
     return 'range';
   }
 }
-
-RangeField.formatMinutes = value => {
-  value = value / 60;
-  return `${value} minute${value != 1 ? 's' : ''}`;
-};
-
-RangeField.defaultProps = {
-  onChange: value => {},
-  formatLabel: value => value,
-  min: 0,
-  max: 100,
-  step: 1,
-  snap: true,
-  allowedValues: null
-};

+ 1 - 1
src/sentry/static/sentry/app/components/selectInput.jsx

@@ -56,7 +56,7 @@ const SelectInput = React.createClass({
     this.destroy();
   },
 
-  getValue() {
+  getSelect2Value() {
     return this.select2.getValue();
   },
 

+ 2 - 2
src/sentry/static/sentry/app/plugins/components/settings.jsx

@@ -7,8 +7,8 @@ import LoadingIndicator from '../../components/loadingIndicator';
 import {t, tct} from '../../locale';
 
 class PluginSettings extends PluginComponentBase {
-  constructor(props) {
-    super(props);
+  constructor(props, context) {
+    super(props, context);
 
     Object.assign(this.state, {
       fieldList: null,

+ 2 - 2
src/sentry/static/sentry/app/views/asyncView.jsx

@@ -7,8 +7,8 @@ import RouteError from './routeError';
 import {Client} from '../api';
 
 class AsyncView extends React.Component {
-  constructor(props) {
-    super(props);
+  constructor(props, context) {
+    super(props, context);
 
     this.fetchData = AsyncView.errorHandler(this, this.fetchData.bind(this));
     this.render = AsyncView.errorHandler(this, this.render.bind(this));

Some files were not shown because too many files changed in this diff