Skip to content

Commit

Permalink
Merge pull request #6178 from gabina/data-rearchitecture-sync-with-ma…
Browse files Browse the repository at this point in the history
…ster

[Data rearchitecture] Sync with master
  • Loading branch information
gabina authored Feb 7, 2025
2 parents 1303fdb + 2daf393 commit d8af364
Show file tree
Hide file tree
Showing 119 changed files with 2,061 additions and 654 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@
/config/newrelic.yml
/config/secrets.yml
/dockerAuth.json
/fixtures
/fixtures/vcr_cassettes/*
!/fixtures/vcr_cassettes/cached/
!/fixtures/vcr_cassettes/cached/*
/node_modules
/js_coverage
/vendor/*
Expand Down
26 changes: 14 additions & 12 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -183,9 +183,9 @@ GEM
launchy
chartkick (4.2.1)
choice (0.2.0)
climate_control (0.2.0)
climate_control (1.2.0)
coderay (1.1.3)
concurrent-ruby (1.2.0)
concurrent-ruby (1.3.4)
connection_pool (2.3.0)
crack (0.4.5)
rexml
Expand Down Expand Up @@ -301,7 +301,7 @@ GEM
http-cookie (1.0.5)
domain_name (~> 0.5)
http_accept_language (2.1.1)
i18n (1.12.0)
i18n (1.14.6)
concurrent-ruby (~> 1.0)
i18n-js (4.2.2)
glob (>= 0.4.0)
Expand All @@ -311,17 +311,18 @@ GEM
activesupport (>= 5.0.0)
json (2.6.2)
jwt (2.5.0)
kt-paperclip (7.2.0)
kt-paperclip (7.2.2)
activemodel (>= 4.2.0)
activesupport (>= 4.2.0)
marcel (~> 1.0.1)
mime-types
terrapin (~> 0.6.0)
terrapin (>= 0.6.0, < 2.0)
launchy (2.5.0)
addressable (~> 2.7)
listen (3.7.0)
rb-fsevent (~> 0.10, >= 0.10.3)
rb-inotify (~> 0.9, >= 0.9.10)
logger (1.6.5)
loofah (2.19.1)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
Expand All @@ -330,15 +331,16 @@ GEM
mini_mime (>= 0.1.1)
mailgun-ruby (1.2.8)
rest-client (>= 2.0.2)
marcel (1.0.2)
marcel (1.0.4)
matrix (0.4.2)
memory_profiler (1.0.0)
method_source (1.0.0)
mime-types (3.4.1)
mime-types (3.6.0)
logger
mime-types-data (~> 3.2015)
mime-types-data (3.2022.0105)
mime-types-data (3.2025.0107)
mini_mime (1.1.2)
minitest (5.17.0)
minitest (5.25.4)
msgpack (1.5.4)
multipart-post (2.2.3)
mysql2 (0.5.4)
Expand Down Expand Up @@ -576,12 +578,12 @@ GEM
stackprof (0.2.23)
strscan (3.0.1)
temple (0.8.2)
terrapin (0.6.0)
climate_control (>= 0.0.3, < 1.0)
terrapin (1.0.1)
climate_control
thor (1.2.1)
tilt (2.0.10)
timeout (0.3.0)
tzinfo (2.0.5)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unf (0.1.4)
unf_ext
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ const ArticleGraphs = ({ article }) => {
}

let radioInput;
if (articleData?.[0].wp10) {
if (articleData?.length > 0 && articleData?.[0]?.wp10) {
radioInput = (
<div>
<div className="input-row">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ export class ArticleScroll {
// Scrolling Logic, Scrolls to paragraph that contains revision by user
scrollTo(name, scrollBox) {
this.bump = false;
const paragraphs = this.scrollObject[name].filteredParagraphs;
const paragraphs = this.scrollObject[name]?.filteredParagraphs || [];
const length = paragraphs.length;
this.nextPosition = paragraphs[this.scrollObject[name].index].coordinates;
this.nextPosition = paragraphs[this.scrollObject[name]?.index]?.coordinates ?? null;

// Finds closest edit if user switchs to a different editor
if (name !== this.currentName && this.currentName !== null) {
Expand Down
4 changes: 1 addition & 3 deletions app/assets/javascripts/components/common/calendar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,7 @@ const Calendar = createReactClass({
}
}

course.day_exceptions = exceptions.join(',');
course.no_day_exceptions = (compact(exceptions).length === 0);
return this.props.updateCourse(course);
return this.props.updateCourse({ ...course, day_exceptions: exceptions.join(','), no_day_exceptions: (compact(exceptions).length === 0) });
},
selectWeekday(e, weekday) {
let weekdays;
Expand Down
8 changes: 5 additions & 3 deletions app/assets/javascripts/components/common/list.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,11 @@ const List = ({
const persistAreaElement = persistAreaElements[i];
if (fixHeader) {
const floatingHeaderRow = persistAreaElements[i].getElementsByClassName('floatingHeader')[0];
const style = window.getComputedStyle(persistAreaElement);
const width = style.getPropertyValue('width');
floatingHeaderRow.style.width = width;
if (floatingHeaderRow) {
const style = window.getComputedStyle(persistAreaElement);
const width = style.getPropertyValue('width');
floatingHeaderRow.style.width = width;
}
}
const offset = persistAreaElement.offsetTop;
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
Expand Down
25 changes: 12 additions & 13 deletions app/assets/javascripts/components/high_order/conditional.jsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,24 @@
import React from 'react';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';

// Enables DRY and simple conditional components
// Renders items when 'show' prop is undefined

const Conditional = function (Component) {
return createReactClass({
displayName: `Conditional${Component.displayName}`,
const ConditionalComponent = (props) => {
if (props.show === undefined || props.show) {
return (<Component {...props} />);
}
return false;
};

propTypes: {
show: PropTypes.bool
},
ConditionalComponent.displayName = `Conditional${Component.displayName}`;

render() {
if (this.props.show === undefined || this.props.show) {
return (<Component {...this.props} />);
}
return false;
}
});
ConditionalComponent.propTypes = {
show: PropTypes.bool
};

return ConditionalComponent;
};

export default Conditional;
97 changes: 47 additions & 50 deletions app/assets/javascripts/components/high_order/editable_redux.jsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// Used by any component that requires "Edit", "Save", and "Cancel" buttons

import React from 'react';
import React, { useState, useCallback } from 'react';
import { connect } from 'react-redux';
import createReactClass from 'create-react-class';
import PropTypes from 'prop-types';
import { resetValidations } from '../../actions/validation_actions';
import { isValid, editPermissions } from '../../selectors';
Expand All @@ -17,79 +16,77 @@ const mapDispatchToProps = {
};

const EditableRedux = (Component, Label) => {
const editableComponent = createReactClass({
displayName: 'EditableRedux',
propTypes: {
course_id: PropTypes.any,
current_user: PropTypes.object,
editable: PropTypes.bool,
resetState: PropTypes.func,
persistCourse: PropTypes.func.isRequired,
nameHasChanged: PropTypes.func.isRequired,
isValid: PropTypes.bool.isRequired,
resetValidations: PropTypes.func.isRequired
},

getInitialState() {
return { editable: this.state ? this.state.editable : false };
},

cancelChanges() {
if (typeof (this.props.resetState) === 'function') {
this.props.resetState();
const EditableWrapper = (props) => {
const [editable, setEditable] = useState(false);

const cancelChanges = useCallback(() => {
if (typeof props.resetState === 'function') {
props.resetState();
}
this.props.resetValidations();
return this.toggleEditable();
},
props.resetValidations();
toggleEditable();
}, [props.resetState, props.resetValidations]);

saveChanges() {
const saveChanges = useCallback(() => {
// If there are validation problems, show error message
if (!this.props.isValid) {
if (!props.isValid) {
return alert(I18n.t('error.form_errors'));
}

// If the course slug has not changed, persist the data and exit edit mode
if (!this.props.nameHasChanged()) {
this.props.persistCourse(this.props.course_id);
return this.toggleEditable();
if (!props.nameHasChanged()) {
props.persistCourse(props.course_id);
return toggleEditable();
}

// If the course has been renamed, we first warn the user that this is happening.
if (confirm(I18n.t('editable.rename_confirmation'))) {
return this.props.persistCourse(this.props.course_id, true);
return props.persistCourse(props.course_id, true);
}
return this.cancelChanges();
},
return cancelChanges();
}, [props.isValid, props.nameHasChanged, props.persistCourse, props.course_id, cancelChanges]);

toggleEditable() {
return this.setState({ editable: !this.state.editable });
},
const toggleEditable = useCallback(() => {
setEditable(prev => !prev);
}, []);

controls() {
if (!this.props.editPermissions) { return null; }
const controls = useCallback(() => {
if (!props.editPermissions) { return null; }

if (this.state.editable) {
if (editable) {
return (
<div className="controls">
<button onClick={this.cancelChanges} className="button">{I18n.t('editable.cancel')}</button>
<button onClick={this.saveChanges} className="dark button">{I18n.t('editable.save')}</button>
<button onClick={cancelChanges} className="button">{I18n.t('editable.cancel')}</button>
<button onClick={saveChanges} className="dark button">{I18n.t('editable.save')}</button>
</div>
);
} else if (this.props.editable === undefined || this.props.editable) {
} else if (props.editable === undefined || props.editable) {
return (
<div className="controls">
<button onClick={this.toggleEditable} className="dark button">{Label}</button>
<button onClick={toggleEditable} className="dark button">{Label}</button>
</div>
);
}
},
}, [props.editPermissions, editable, props.editable, cancelChanges, saveChanges, toggleEditable]);

render() {
return <Component {...this.props} {...this.state} disableSave={this.disableSave} controls={this.controls} />;
}
});
return connect(mapStateToProps, mapDispatchToProps)(editableComponent);
};
return <Component {...props} editable={editable} controls={controls} />;
};

EditableWrapper.displayName = 'EditableRedux';

EditableWrapper.propTypes = {
course_id: PropTypes.any,
current_user: PropTypes.object,
editable: PropTypes.bool,
resetState: PropTypes.func,
persistCourse: PropTypes.func.isRequired,
nameHasChanged: PropTypes.func.isRequired,
isValid: PropTypes.bool.isRequired,
resetValidations: PropTypes.func.isRequired,
editPermissions: PropTypes.bool
};

return connect(mapStateToProps, mapDispatchToProps)(EditableWrapper);
};

export default EditableRedux;
2 changes: 1 addition & 1 deletion app/assets/javascripts/components/overview/tag_list.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const TagList = ({ tags, course }) => {
const comma = (index !== lastIndex) ? ', ' : '';
return <span key={`${tag.tag}${tag.id}`}>{tag.tag}{comma}</span>;
})
: I18n.t('courses.none'));
: <span>{I18n.t('courses.none')}</span>);

return (
<span key="tags_list" className="tags">
Expand Down
Loading

0 comments on commit d8af364

Please sign in to comment.