Skip to content

Commit

Permalink
Merge branch 'master' into new_localization
Browse files Browse the repository at this point in the history
  • Loading branch information
SemaiCZE committed Oct 30, 2017
2 parents d0ec6a0 + 91aefbc commit dede7eb
Show file tree
Hide file tree
Showing 14 changed files with 383 additions and 291 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ NODE_ENV=development
API_BASE=http://localhost:4000/v1
PORT=8080
WEBPACK_DEV_SERVER_PORT=8081
TITLE=ReCodEx
ALLOW_NORMAL_REGISTRATION=true
ALLOW_LDAP_REGISTRATION=false
ALLOW_CAS_REGISTRATION=true
```

## Run Dev
Expand All @@ -37,7 +41,7 @@ yarn build
yarn start
```

Consider using [PM2](http://pm2.keymetrics.io/) or similar tool to run the `yarn start` command to prevent crashes of the web service.
Consider using [PM2](http://pm2.keymetrics.io/) or similar tool to run the `yarn start` command to prevent crashes of the web service. It is wise to use watch mode of PM2 in `prod/` subdirectory and deploy the app using `yarn deploy` command.

## License

Expand Down
32 changes: 2 additions & 30 deletions src/components/forms/EditAssignmentForm/EditAssignmentForm.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,17 @@
import React from 'react';
import PropTypes from 'prop-types';
import { canUseDOM } from 'exenv';
import { reduxForm, Field, FieldArray, touch } from 'redux-form';
import { FormattedHTMLMessage, FormattedMessage } from 'react-intl';
import { FormattedMessage } from 'react-intl';
import { Alert, HelpBlock } from 'react-bootstrap';
import isNumeric from 'validator/lib/isNumeric';

import FormBox from '../../widgets/FormBox';
import {
DatetimeField,
TextField,
CheckboxField,
SourceCodeField
} from '../Fields';
import { DatetimeField, TextField, CheckboxField } from '../Fields';
import LocalizedTextsFormField from '../LocalizedTextsFormField';
import SubmitButton from '../SubmitButton';

import { validateAssignment } from '../../../redux/modules/assignments';

if (canUseDOM) {
require('codemirror/mode/yaml/yaml');
}

const EditAssignmentForm = ({
initialValues: assignment,
anyTouched,
Expand Down Expand Up @@ -94,24 +84,6 @@ const EditAssignmentForm = ({
component={LocalizedTextsFormField}
/>

<Field
name="scoreConfig"
component={SourceCodeField}
mode="yaml"
label={
<FormattedMessage
id="app.editAssignmentForm.scoreConfig"
defaultMessage="Score configuration:"
/>
}
/>
<HelpBlock>
<FormattedHTMLMessage
id="app.editAssignmentForm.moreAboutScoreConfig"
defaultMessage="Read more about <a href='https://github.com/ReCodEx/wiki/wiki/Assignments#scoring'>score configuration</a> syntax."
/>
</HelpBlock>

<Field
name="firstDeadline"
component={DatetimeField}
Expand Down
94 changes: 94 additions & 0 deletions src/components/forms/EditScoreConfigForm/EditScoreConfigForm.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React from 'react';
import PropTypes from 'prop-types';
import { canUseDOM } from 'exenv';
import { reduxForm, Field } from 'redux-form';
import { FormattedMessage } from 'react-intl';
import { Alert } from 'react-bootstrap';

import { SourceCodeField } from '../Fields';
import SubmitButton from '../SubmitButton';

if (canUseDOM) {
require('codemirror/mode/yaml/yaml');
}

const EditScoreConfigForm = ({
anyTouched,
submitting,
handleSubmit,
hasFailed = false,
hasSucceeded = false,
invalid
}) =>
<div>
{hasFailed &&
<Alert bsStyle="danger">
<FormattedMessage
id="app.editScoreConfigForm.failed"
defaultMessage="Saving failed. Please try again later."
/>
</Alert>}

<Field
name="scoreConfig"
component={SourceCodeField}
mode="yaml"
label={
<FormattedMessage
id="app.editScoreConfigForm.scoreConfig"
defaultMessage="Score configuration:"
/>
}
/>

<div className="text-center">
<SubmitButton
id="editEnvironmentConfig"
invalid={invalid}
submitting={submitting}
hasSucceeded={hasSucceeded}
dirty={anyTouched}
hasFailed={hasFailed}
handleSubmit={handleSubmit}
messages={{
submit: (
<FormattedMessage
id="app.editScoreConfigForm.submit"
defaultMessage="Change configuration"
/>
),
submitting: (
<FormattedMessage
id="app.editScoreConfigForm.submitting"
defaultMessage="Saving configuration ..."
/>
),
success: (
<FormattedMessage
id="app.editScoreConfigForm.success"
defaultMessage="Configuration was changed."
/>
)
}}
/>
</div>
</div>;

EditScoreConfigForm.propTypes = {
handleSubmit: PropTypes.func.isRequired,
anyTouched: PropTypes.bool,
submitting: PropTypes.bool,
hasFailed: PropTypes.bool,
hasSucceeded: PropTypes.bool,
invalid: PropTypes.bool
};

const validate = () => {
const errors = {};
return errors;
};

export default reduxForm({
form: 'editScoreConfig',
validate
})(EditScoreConfigForm);
1 change: 1 addition & 0 deletions src/components/forms/EditScoreConfigForm/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default from './EditScoreConfigForm';
27 changes: 12 additions & 15 deletions src/components/helpers/SourceCodeViewer/SourceCodeViewer.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,27 +32,24 @@ const getMode = ext => {
};

const SourceCodeViewer = (
{ name, content = '', lineNumbers = true, height },
{ name, content = '', lineNumbers = true },
{ userSettings: { vimMode = false, darkTheme = false } }
) =>
height
? <AceEditor
value={content}
mode={getMode(name.split('.').pop())}
keyboardHandler={vimMode ? 'vim' : undefined}
theme={darkTheme ? 'monokai' : 'github'}
name="source-code-viewer"
width="100%"
height={`${height}px`}
editorProps={{ $blockScrolling: true, $autoScrollEditorIntoView: true }}
/>
: null;
<AceEditor
value={content}
mode={getMode(name.split('.').pop())}
keyboardHandler={vimMode ? 'vim' : undefined}
theme={darkTheme ? 'monokai' : 'github'}
name="source-code-viewer"
width="100%"
height="100%"
editorProps={{ $blockScrolling: true, $autoScrollEditorIntoView: true }}
/>;

SourceCodeViewer.propTypes = {
name: PropTypes.string.isRequired,
content: PropTypes.string,
lineNumbers: PropTypes.bool,
height: PropTypes.number
lineNumbers: PropTypes.bool
};

SourceCodeViewer.contextTypes = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ import SourceCodeViewer from '../../components/helpers/SourceCodeViewer';
import styles from './sourceCode.less';

class SourceCodeViewerContainer extends Component {
state = { height: null };

componentWillMount() {
const { fileId, loadAsync } = this.props;
if (fileId !== null) {
Expand All @@ -31,45 +29,13 @@ class SourceCodeViewerContainer extends Component {
}
}

onModalEntered() {
if (this.state.height === null) {
const { headerRef, bodyRef, footerRef } = this;
const height =
window.innerHeight -
headerRef.clientHeight -
bodyRef.clientHeight -
footerRef.clientHeight;
this.setState({ height });
}
}

onModalEnteredWhileLoading() {
if (this.state.height === null) {
const { loadingHeaderRef, loadingBodyRef, loadingFooterRef } = this;
const height =
window.innerHeight -
loadingHeaderRef.clientHeight -
loadingBodyRef.clientHeight -
loadingFooterRef.clientHeight;
this.setState({ height });
} else {
// console.log('already has height', this.state.height);
}
}

render() {
const { show, onHide, download, file, code } = this.props;
const { height } = this.state;
const { show, onHide, download, file, content } = this.props;
return (
<ResourceRenderer
loading={
<Modal
show={show}
onHide={onHide}
dialogClassName={styles.modal}
onEntered={() => this.onModalEnteredWhileLoading()}
>
<div ref={header => (this.loadingHeaderRef = header)}>
<Modal show={show} onHide={onHide} dialogClassName={styles.modal}>
<div>
<Modal.Header closeButton>
<Modal.Title>
<LoadingIcon />{' '}
Expand All @@ -80,12 +46,14 @@ class SourceCodeViewerContainer extends Component {
</Modal.Title>
</Modal.Header>
</div>
<div ref={body => (this.loadingBodyRef = body)}>
<div>
<Modal.Body className={styles.modalBody}>
<SourceCodeViewer content="" name="" />
<div>
<SourceCodeViewer content="" name="" />
</div>
</Modal.Body>
</div>
<div ref={footer => (this.loadingFooterRef = footer)}>
<div>
<Modal.Footer>
<Button disabled>
<DownloadIcon />{' '}
Expand All @@ -98,32 +66,45 @@ class SourceCodeViewerContainer extends Component {
</div>
</Modal>
}
resource={[file, code]}
resource={[file, content]}
>
{(file, code) =>
<Modal
show={show}
onHide={onHide}
dialogClassName={styles.modal}
onEntered={() => this.onModalEntered()}
>
<div ref={header => (this.headerRef = header)}>
{(file, content) =>
<Modal show={show} onHide={onHide} dialogClassName={styles.modal}>
<div>
<Modal.Header closeButton>
<Modal.Title>
{file.name}
</Modal.Title>
</Modal.Header>
</div>
<div ref={body => (this.bodyRef = body)}>
<div>
<Modal.Body className={styles.modalBody}>
<SourceCodeViewer
content={code}
name={file.name}
height={height}
/>
{(content.malformedCharacters || content.tooLarge) &&
<div className="callout callout-warning">
{content.malformedCharacters &&
<p>
<FormattedMessage
id="app.sourceCodeViewer.utf8Warning"
defaultMessage="The source file is not a valid UTF-8 file. Some characters may be displayed incorrectly. Use the download button to see unaltered source file."
/>
</p>}
{content.tooLarge &&
<p>
<FormattedMessage
id="app.sourceCodeViewer.incompleteWarning"
defaultMessage="The selected source file is too large. Only a leading part of the file is displayed here. Use the download button to get the whole file."
/>
</p>}
</div>}
<div>
<SourceCodeViewer
content={content.content}
name={file.name}
/>
</div>
</Modal.Body>
</div>
<div ref={footer => (this.footerRef = footer)}>
<div>
<Modal.Footer>
<Button onClick={() => download(file.id)}>
<DownloadIcon />{' '}
Expand All @@ -147,13 +128,13 @@ SourceCodeViewerContainer.propTypes = {
onHide: PropTypes.func.isRequired,
loadAsync: PropTypes.func.isRequired,
download: PropTypes.func.isRequired,
code: ImmutablePropTypes.map
content: ImmutablePropTypes.map
};

export default connect(
(state, { fileId }) => ({
file: getFile(fileId)(state),
code: getFilesContent(fileId)(state)
content: getFilesContent(fileId)(state)
}),
(dispatch, { fileId }) => ({
loadAsync: () =>
Expand Down
Loading

0 comments on commit dede7eb

Please sign in to comment.