From fcbfe2e5da63e8592a1365859fd65c3c4144aa10 Mon Sep 17 00:00:00 2001 From: Ashwin Srinivasan Date: Fri, 26 Apr 2019 17:01:21 -0400 Subject: [PATCH 01/10] Added option to hide delete button, mask student IDs --- server/public/javascripts/datarow.js | 3 +- server/public/javascripts/datatable.js | 37 ++++++++++--- server/public/javascripts/dataview.js | 11 ++-- server/public/javascripts/dataviewbar.js | 3 +- server/public/javascripts/react/datarow.jsx | 4 +- server/public/javascripts/react/datatable.jsx | 17 +++++- server/public/javascripts/react/dataview.jsx | 7 +-- .../public/javascripts/react/dataviewbar.jsx | 54 ++++++++++--------- server/routes/admin.js | 27 +++++----- server/views/partials/config.hbs | 6 +++ 10 files changed, 109 insertions(+), 60 deletions(-) diff --git a/server/public/javascripts/datarow.js b/server/public/javascripts/datarow.js index 7e36606..0b537fa 100644 --- a/server/public/javascripts/datarow.js +++ b/server/public/javascripts/datarow.js @@ -53,6 +53,7 @@ var DataRow = function (_React$Component) { key: 'render', value: function render() { var _props = this.props, + showStudent = _props.showStudent, _id = _props._id, section = _props.section, student_id = _props.student_id, @@ -76,7 +77,7 @@ var DataRow = function (_React$Component) { React.createElement( 'td', null, - student_id + showStudent ? student_id : '••••••' ), React.createElement( 'td', diff --git a/server/public/javascripts/datatable.js b/server/public/javascripts/datatable.js index 3d8f2e0..00e26af 100644 --- a/server/public/javascripts/datatable.js +++ b/server/public/javascripts/datatable.js @@ -17,10 +17,12 @@ var DataTable = function (_React$Component) { var _this = _possibleConstructorReturn(this, (DataTable.__proto__ || Object.getPrototypeOf(DataTable)).call(this, props)); _this.state = { + studentVisibility: false, lab: '', labActive: false, preserve: false }; + _this.toggleStudentVisibility = _this.toggleStudentVisibility.bind(_this); _this.toggleLab = _this.toggleLab.bind(_this); _this.onChangeLab = _this.onChangeLab.bind(_this); _this.onChangePreserve = _this.onChangePreserve.bind(_this); @@ -29,10 +31,18 @@ var DataTable = function (_React$Component) { } _createClass(DataTable, [{ + key: 'toggleStudentVisibility', + value: function toggleStudentVisibility() { + this.setState(function (_ref) { + var studentVisibility = _ref.studentVisibility; + return { studentVisibility: !studentVisibility }; + }); + } + }, { key: 'toggleLab', value: function toggleLab() { - this.setState(function (_ref) { - var labActive = _ref.labActive; + this.setState(function (_ref2) { + var labActive = _ref2.labActive; return { labActive: !labActive }; }); } @@ -67,7 +77,9 @@ var DataTable = function (_React$Component) { sort = _props.sort, entries = _props.entries, updateSort = _props.updateSort; - var labActive = this.state.labActive; + var _state2 = this.state, + studentVisibility = _state2.studentVisibility, + labActive = _state2.labActive; var columns = [['Section', 'section'], ['Student ID', 'student_id'], ['Score', 'score'], ['Lab', 'lab'], ['Date', 'date'], ['TA', 'ta'], ['Flags', 'flags']]; return React.createElement( @@ -79,10 +91,10 @@ var DataTable = function (_React$Component) { React.createElement( 'tr', null, - columns.map(function (_ref2) { - var _ref3 = _slicedToArray(_ref2, 2), - title = _ref3[0], - name = _ref3[1]; + columns.map(function (_ref3) { + var _ref4 = _slicedToArray(_ref3, 2), + title = _ref4[0], + name = _ref4[1]; return React.createElement( 'th', @@ -172,6 +184,15 @@ var DataTable = function (_React$Component) { { className: 'icon' }, React.createElement('i', { className: 'fas fa-caret-' + (sort[name] > 0 ? 'down' : 'up') }) ) + ), + name === 'student_id' && React.createElement( + 'a', + { className: 'tooltip', 'data-tooltip': 'Toggle visibility', onClick: _this2.toggleStudentVisibility }, + React.createElement( + 'span', + { className: 'icon has-text-info' }, + React.createElement('i', { className: 'fas fa-' + (studentVisibility ? 'eye-slash' : 'eye') }) + ) ) ); }) @@ -181,7 +202,7 @@ var DataTable = function (_React$Component) { 'tbody', null, entries.map(function (entry) { - return React.createElement(DataRow, Object.assign({ key: entry._id }, entry)); + return React.createElement(DataRow, Object.assign({ showStudent: studentVisibility, key: entry._id }, entry)); }) ) ); diff --git a/server/public/javascripts/dataview.js b/server/public/javascripts/dataview.js index cb8b029..0975f7a 100644 --- a/server/public/javascripts/dataview.js +++ b/server/public/javascripts/dataview.js @@ -17,6 +17,7 @@ var DataView = function (_React$Component) { _this.state = { error: null, isLoaded: false, + showData: true, entries: [], filters: { good: true @@ -49,10 +50,9 @@ var DataView = function (_React$Component) { filters: this.state.filters, sort: this.state.sort }).then(function (res) { - return _this2.setState({ - isLoaded: true, - entries: res.data - }); + return _this2.setState(Object.assign({ + isLoaded: true + }, res.data)); }, function (err) { return _this2.setState({ isLoaded: true, @@ -194,6 +194,7 @@ var DataView = function (_React$Component) { var _state = this.state, error = _state.error, isLoaded = _state.isLoaded, + showDelete = _state.showDelete, entries = _state.entries, filters = _state.filters, sort = _state.sort, @@ -221,7 +222,7 @@ var DataView = function (_React$Component) { 'div', null, React.createElement(FilterPane, { filters: filters, filtersActive: filtersActive, toggleFilters: this.toggleFilters, updateFilters: this.updateFilters, getData: this.getData }), - React.createElement(DataViewBar, { entriesCount: entries.length, filters: filters, toggleFilters: this.toggleFilters, updateFilters: this.updateFilters, getData: this.getData, downloadData: this.downloadData, deleteData: this.deleteData }), + React.createElement(DataViewBar, { showDelete: showDelete, entriesCount: entries.length, filters: filters, toggleFilters: this.toggleFilters, updateFilters: this.updateFilters, getData: this.getData, downloadData: this.downloadData, deleteData: this.deleteData }), React.createElement(DataDownload, { isActive: modalActive, toggleModal: this.toggleModal, data: downloadData, type: downloadType }), React.createElement(DataTable, { sort: sort, entries: entries, updateSort: this.updateSort, assignLab: this.assignLab }) ); diff --git a/server/public/javascripts/dataviewbar.js b/server/public/javascripts/dataviewbar.js index 09a2d12..1bb37e2 100644 --- a/server/public/javascripts/dataviewbar.js +++ b/server/public/javascripts/dataviewbar.js @@ -50,6 +50,7 @@ var DataViewBar = function (_React$Component) { key: 'render', value: function render() { var _props = this.props, + showDelete = _props.showDelete, filters = _props.filters, toggleFilters = _props.toggleFilters, updateFilters = _props.updateFilters, @@ -212,7 +213,7 @@ var DataViewBar = function (_React$Component) { ) ) ), - React.createElement( + showDelete && React.createElement( 'p', { className: 'level-item' }, React.createElement( diff --git a/server/public/javascripts/react/datarow.jsx b/server/public/javascripts/react/datarow.jsx index 51d99f5..110db22 100644 --- a/server/public/javascripts/react/datarow.jsx +++ b/server/public/javascripts/react/datarow.jsx @@ -28,14 +28,14 @@ class DataRow extends React.Component { } render() { - const { _id, section, student_id, score, lab, date, ta, flags } = this.props; + const { showStudent, _id, section, student_id, score, lab, date, ta, flags } = this.props; const { good, isActive } = this.state; return {section} - {student_id} + {showStudent ? student_id : '••••••'} {score} diff --git a/server/public/javascripts/react/datatable.jsx b/server/public/javascripts/react/datatable.jsx index 0232b12..20e2b7a 100644 --- a/server/public/javascripts/react/datatable.jsx +++ b/server/public/javascripts/react/datatable.jsx @@ -2,16 +2,22 @@ class DataTable extends React.Component { constructor(props) { super(props); this.state = { + studentVisibility: false, lab: '', labActive: false, preserve: false, }; + this.toggleStudentVisibility = this.toggleStudentVisibility.bind(this); this.toggleLab = this.toggleLab.bind(this); this.onChangeLab = this.onChangeLab.bind(this); this.onChangePreserve = this.onChangePreserve.bind(this); this.sendLab = this.sendLab.bind(this); } + toggleStudentVisibility() { + this.setState(({ studentVisibility }) => ({ studentVisibility: !studentVisibility })); + } + toggleLab() { this.setState(({ labActive }) => ({ labActive: !labActive })); } @@ -34,7 +40,7 @@ class DataTable extends React.Component { render() { const { sort, entries, updateSort } = this.props; - const { labActive } = this.state; + const { studentVisibility, labActive } = this.state; const columns = [ ['Section', 'section'], ['Student ID', 'student_id'], @@ -98,13 +104,20 @@ class DataTable extends React.Component { } + {name === 'student_id' && + + + + + + } ))} {entries.map(entry => ( - + ))} ; diff --git a/server/public/javascripts/react/dataview.jsx b/server/public/javascripts/react/dataview.jsx index 5c24ec8..d6eac63 100644 --- a/server/public/javascripts/react/dataview.jsx +++ b/server/public/javascripts/react/dataview.jsx @@ -4,6 +4,7 @@ class DataView extends React.Component { this.state = { error: null, isLoaded: false, + showData: true, entries: [], filters: { good: true, @@ -32,7 +33,7 @@ class DataView extends React.Component { sort: this.state.sort, }).then(res => this.setState({ isLoaded: true, - entries: res.data, + ...res.data, }), err => this.setState({ isLoaded: true, error: err, @@ -135,7 +136,7 @@ class DataView extends React.Component { render() { const { - error, isLoaded, entries, filters, sort, filtersActive, modalActive, downloadData, downloadType, + error, isLoaded, showDelete, entries, filters, sort, filtersActive, modalActive, downloadData, downloadType, } = this.state; if (error) { return
Error: {error.message}
; @@ -145,7 +146,7 @@ class DataView extends React.Component { } return
- +
; diff --git a/server/public/javascripts/react/dataviewbar.jsx b/server/public/javascripts/react/dataviewbar.jsx index 88bad5a..5bcfbd9 100644 --- a/server/public/javascripts/react/dataviewbar.jsx +++ b/server/public/javascripts/react/dataviewbar.jsx @@ -28,7 +28,7 @@ class DataViewBar extends React.Component { render() { const { - filters, toggleFilters, updateFilters, getData, downloadData, + showDelete, filters, toggleFilters, updateFilters, getData, downloadData, } = this.props; const { deleteConfirmation, deleteActive } = this.state; return ; } diff --git a/server/routes/admin.js b/server/routes/admin.js index 7702dc4..1860244 100644 --- a/server/routes/admin.js +++ b/server/routes/admin.js @@ -35,7 +35,7 @@ function parseDataQuery(query) { const options = {}; const { filters } = query; const { - startDate, endDate, flags, good, + startDate, endDate, flags, } = filters; // special case: start and end date must be used together if (startDate && endDate) { @@ -141,17 +141,20 @@ router.post('/rawdata', (req, res, next) => { Entry.find(options).sort(sort).exec((err, entries) => { if (err) return next(createError(500, err)); // send data after some modifications - res.send(entries.map((entry) => { - // convert each entry to json to get rid of helper functions - const newEntry = entry.toJSON(); - // prettify date - newEntry.date = helpers.prettyDate(entry.date); - // if entry has attempt flag, prettify the time interval - if (newEntry.flags && newEntry.flags.attemptDiff) { - newEntry.flags.attemptDiff = helpers.prettyDiff(newEntry.flags.attemptDiff); - } - return newEntry; - })); + res.send({ + showDelete: config.get('showDelete'), + entries: entries.map((entry) => { + // convert each entry to json to get rid of helper functions + const newEntry = entry.toJSON(); + // prettify date + newEntry.date = helpers.prettyDate(entry.date); + // if entry has attempt flag, prettify the time interval + if (newEntry.flags && newEntry.flags.attemptDiff) { + newEntry.flags.attemptDiff = helpers.prettyDiff(newEntry.flags.attemptDiff); + } + return newEntry; + }), + }); }); }); diff --git a/server/views/partials/config.hbs b/server/views/partials/config.hbs index 38906b8..3ea636a 100644 --- a/server/views/partials/config.hbs +++ b/server/views/partials/config.hbs @@ -48,6 +48,12 @@ + +