diff --git a/build/dev-dist/audit_log-8f3ec9b285211b3b3934.js b/build/dev-dist/audit_log-7a0e288eaf6a936df408.js
similarity index 91%
rename from build/dev-dist/audit_log-8f3ec9b285211b3b3934.js
rename to build/dev-dist/audit_log-7a0e288eaf6a936df408.js
index 8d4ab0ea..45e50c89 100644
--- a/build/dev-dist/audit_log-8f3ec9b285211b3b3934.js
+++ b/build/dev-dist/audit_log-7a0e288eaf6a936df408.js
@@ -94,7 +94,8 @@ var result_changeset_name_map = {
'evidence_name': gettext('Evidence Name'),
'date': gettext('Date'),
'target': gettext('Target'),
- 'value': gettext('Value')
+ 'value': gettext('Value'),
+ 'id': gettext('ID')
};
var ResultChangeset = function ResultChangeset(_ref) {
@@ -102,11 +103,15 @@ var ResultChangeset = function ResultChangeset(_ref) {
name = _ref.name;
if (name == 'evidence_url') {
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", null, result_changeset_name_map[name], ": ", data != 'N/A' ? react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("a", {
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "change__field"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("strong", null, result_changeset_name_map[name]), ": ", data != 'N/A' ? react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("a", {
href: data
}, "Link") : data);
} else {
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", null, result_changeset_name_map[name], ": ", data);
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "change__field"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("strong", null, result_changeset_name_map[name]), ": ", data);
}
};
@@ -118,7 +123,9 @@ var program_dates_changset_name_map = {
var ProgramDatesChangeset = function ProgramDatesChangeset(_ref2) {
var data = _ref2.data,
name = _ref2.name;
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", null, program_dates_changset_name_map[name], ": ", data);
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "change__field"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("strong", null, program_dates_changset_name_map[name]), ": ", data);
};
var indicator_changeset_name_map = {
@@ -156,17 +163,24 @@ var IndicatorChangeset = function IndicatorChangeset(_ref3) {
}();
if (name == 'targets') {
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", null, "Targets"), Object.entries(data).map(function (_ref4) {
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog__change__targets"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("h4", {
+ className: "text-small"
+ }, gettext('Targets changed')), Object.entries(data).map(function (_ref4) {
var _ref5 = _slicedToArray(_ref4, 2),
id = _ref5[0],
target = _ref5[1];
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", {
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "change__field",
key: id
- }, target.name, ": ", target.value);
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("strong", null, target.name, ":"), " ", target.value);
}));
} else {
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", null, indicator_changeset_name_map[name], ": ", mapped_data !== null && mapped_data !== undefined ? mapped_data.toString() : 'N/A');
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "change__field"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("strong", null, indicator_changeset_name_map[name], ":"), " ", mapped_data !== null && mapped_data !== undefined ? mapped_data.toString() : 'N/A');
}
};
@@ -228,46 +242,70 @@ function (_React$Component) {
var IndexView = Object(mobx_react__WEBPACK_IMPORTED_MODULE_1__["observer"])(function (_ref6) {
var store = _ref6.store;
return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
- id: "audit-log-index-view",
- className: "container-fluid row"
+ id: "audit-log-index-view"
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
className: "admin-list__controls"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "controls__bulk-actions"
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "controls__buttons"
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("a", {
- className: "btn btn-link btn-secondary btn-sm",
+ className: "btn btn-secondary btn-sm",
href: "/api/tola_management/program/".concat(store.program_id, "/export_audit_log")
- }, gettext("Export to Excel"))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
- className: "col col-sm-12 admin-list"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("i", {
+ className: "fas fa-download"
+ }), gettext("Excel")))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "admin-list__table"
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(components_loading_spinner__WEBPACK_IMPORTED_MODULE_8__["default"], {
isLoading: store.fetching
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("table", {
- className: "admin-list__table"
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("thead", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("Date and Time")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("No.")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
- width: "25%"
- }, gettext("Indicator")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("User")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("Organization")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("Change Type")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("Previous Entry")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("New Entry")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("Rationale")))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tbody", null, store.log_rows.map(function (data) {
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", {
+ className: "table table-sm table-bordered bg-white text-small changelog"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("thead", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap"
+ }, gettext("Date and Time")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap"
+ }, gettext("No.")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap"
+ }, gettext("Indicator")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap"
+ }, gettext("User")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap"
+ }, gettext("Organization")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap"
+ }, gettext("Change Type")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap"
+ }, gettext("Previous Entry")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap"
+ }, gettext("New Entry")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap"
+ }, gettext("Rationale")))), store.log_rows.map(function (data) {
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tbody", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", {
+ className: "changelog__entry__header is-expanded"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, data.date), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, data.indicator ? data.indicator.number : 'N/A'), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, data.indicator ? data.indicator.name : 'N/A'), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, data.user), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, data.organization), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, map_pretty_change_type(data.change_type)), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null)), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", {
+ className: "changelog__entry__row",
key: data.id
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, data.date), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, data.indicator ? data.indicator.number : 'N/A'), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, data.indicator ? data.indicator.name : 'N/A'), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, data.user), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, data.organization), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, map_pretty_change_type(data.change_type)), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
- className: "expand-section"
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(components_expander__WEBPACK_IMPORTED_MODULE_7__["default"], null, data.diff_list.map(function (changeset) {
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
+ className: "changelog__change--prev"
+ }, data.diff_list.map(function (changeset) {
return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangesetEntry, {
key: changeset.name,
name: changeset.name,
type: data.change_type,
data: changeset.prev
});
- }))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
- className: "expand-section"
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(components_expander__WEBPACK_IMPORTED_MODULE_7__["default"], null, data.diff_list.map(function (changeset) {
+ })), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
+ className: "changelog__change--new"
+ }, data.diff_list.map(function (changeset) {
return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangesetEntry, {
key: changeset.name,
name: changeset.name,
type: data.change_type,
data: changeset.new
});
- }))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
- className: "expand-section"
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(components_expander__WEBPACK_IMPORTED_MODULE_7__["default"], null, data.rationale)));
- })))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ })), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
+ className: "changelog__change--rationale"
+ }, data.rationale)));
+ }))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
className: "admin-list__metadata"
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
className: "metadata__count text-muted text-small"
@@ -557,13 +595,17 @@ function (_React$Component) {
value: function render() {
var _this2 = this;
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog-entry"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
ref: this.ref,
- className: "expander",
+ className: "changelog-entry__expanding",
style: {
height: !this.state.expanded && (this.props.height || 50)
}
- }, this.props.children), this.state.overflowing && react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("a", {
+ }, this.props.children), this.state.overflowing && react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog-entry__expand-trigger"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("a", {
href: "",
onClick: function onClick(e) {
return _this2.toggleExpanded(e);
@@ -1062,4 +1104,4 @@ function () {
/***/ })
},[["6bbB","runtime","vendors"]]]);
-//# sourceMappingURL=audit_log-8f3ec9b285211b3b3934.js.map
\ No newline at end of file
+//# sourceMappingURL=audit_log-7a0e288eaf6a936df408.js.map
\ No newline at end of file
diff --git a/build/dev-dist/audit_log-7a0e288eaf6a936df408.js.map b/build/dev-dist/audit_log-7a0e288eaf6a936df408.js.map
new file mode 100644
index 00000000..4f5eb6ac
--- /dev/null
+++ b/build/dev-dist/audit_log-7a0e288eaf6a936df408.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"audit_log-7a0e288eaf6a936df408.js","sources":["webpack:///./js/pages/tola_management_pages/audit_log/views.js","webpack:///./js/components/virtualized-react-select.js","webpack:///./js/pages/tola_management_pages/audit_log/index.js","webpack:///./js/components/loading-spinner.js","webpack:///./js/components/expander.js","webpack:///./js/components/pagination.js","webpack:///./js/components/management-table.js","webpack:///./js/api.js","webpack:///./js/components/checkboxed-multi-select.js","webpack:///./js/pages/tola_management_pages/audit_log/api.js","webpack:///./js/pages/tola_management_pages/audit_log/models.js"],"sourcesContent":["import React from 'react';\nimport { observer } from \"mobx-react\"\nimport Select from 'react-select'\nimport classNames from 'classnames'\nimport ManagementTable from 'components/management-table'\nimport Pagination from 'components/pagination'\nimport CheckboxedMultiSelect from 'components/checkboxed-multi-select'\nimport Expander from 'components/expander'\n\nimport LoadingSpinner from 'components/loading-spinner'\n\nconst pretty_change_type = {\n indicator_changed: gettext('Indicator changed'),\n indicator_created: gettext('Indicator created'),\n indicator_deleted: gettext('Indicator deleted'),\n result_changed: gettext('Result changed'),\n result_created: gettext('Result created'),\n result_deleted: gettext('Result deleted'),\n program_dates_changed: gettext('Program Dates Changed')\n}\n\nconst map_pretty_change_type = change_type => pretty_change_type[change_type]\n\nconst units_of_measure_type = {\n 1: gettext(\"Number\"),\n 2: gettext(\"Percentage\")\n}\nconst map_unit_of_measure_type = id => units_of_measure_type[id]\n\nconst directions_of_change = {\n 1: gettext(\"N/A\"),\n 2: gettext(\"Increase (+)\"),\n 3: gettext(\"Decrease (-)\"),\n}\nconst map_direction_of_change = id => directions_of_change[id]\n\nconst result_changeset_name_map = {\n 'evidence_url': gettext('Evidence Url'),\n 'evidence_name': gettext('Evidence Name'),\n 'date': gettext('Date'),\n 'target': gettext('Target'),\n 'value': gettext('Value'),\n 'id': gettext('ID'),\n}\n\nconst ResultChangeset = ({data, name}) => {\n if(name == 'evidence_url') {\n return
{result_changeset_name_map[name]} : {(data != 'N/A')?
Link :data}
\n } else {\n return {result_changeset_name_map[name]} : {data}
\n }\n}\n\nconst program_dates_changset_name_map = {\n 'start_date': gettext('Start Date'),\n 'end_date': gettext('End Date')\n}\n\nconst ProgramDatesChangeset = ({data, name}) => {\n return {program_dates_changset_name_map[name]} : {data}
\n}\n\nconst indicator_changeset_name_map = {\n name: gettext('Name'),\n unit_of_measure: gettext('Unit of Measure'),\n unit_of_measure_type: gettext('Unit of Measure Type'),\n is_cumulative: gettext('Is Cumulative'),\n lop_target: gettext('LOP Target'),\n direction_of_change: gettext('Direction of Change'),\n rationale_for_target: gettext('Rationale for Target'),\n baseline_value: gettext('Baseline Value'),\n baseline_na: gettext('Baseline N/A'),\n}\n\nconst IndicatorChangeset = ({data, name}) => {\n const mapped_data = (() => {\n if (data == 'N/A') return data\n\n switch(name) {\n case 'unit_of_measure_type':\n return map_unit_of_measure_type(data)\n break\n case 'direction_of_change':\n return map_direction_of_change(data)\n break\n default:\n return data\n break\n }\n })()\n if(name == 'targets') {\n return \n
{gettext('Targets changed')} \n {Object.entries(data).map(([id, target]) => {\n return
{target.name}: {target.value}
\n })}\n
\n } else {\n return \n {indicator_changeset_name_map[name]}: {(mapped_data !== null && mapped_data !== undefined)?mapped_data.toString():'N/A'}\n
\n }\n}\n\nclass ChangesetEntry extends React.Component {\n renderType(type, data, name) {\n switch(type) {\n case 'indicator_changed':\n case 'indicator_created':\n case 'indicator_deleted':\n return \n break\n case 'result_changed':\n case 'result_created':\n case 'result_deleted':\n return \n break\n case 'program_dates_changed':\n return \n break\n }\n }\n\n render() {\n const {data, type, name} = this.props\n return this.renderType(type, data, name)\n }\n}\n\nexport const IndexView = observer(\n ({store}) => {\n return \n\n
\n
\n
\n \n \n \n {gettext(\"Date and Time\")} \n {gettext(\"No.\")} \n {gettext(\"Indicator\")} \n {gettext(\"User\")} \n {gettext(\"Organization\")} \n {gettext(\"Change Type\")} \n {gettext(\"Previous Entry\")} \n {gettext(\"New Entry\")} \n {gettext(\"Rationale\")} \n \n \n {store.log_rows.map(data => \n \n {data.date} \n {(data.indicator)?data.indicator.number:'N/A'} \n {(data.indicator)?data.indicator.name:'N/A'} \n {data.user} \n {data.organization} \n {map_pretty_change_type(data.change_type)} {/* SWEET FANCY MOSES WHAT IS THIS */}\n \n \n \n \n \n \n \n \n \n \n \n \n {data.diff_list.map(changeset => {\n return \n })}\n \n \n {data.diff_list.map(changeset => {\n return \n })}\n \n {data.rationale} \n \n \n )}\n
\n \n
\n
{store.entries_count?`${store.entries_count} ${gettext(\"entries\")}`:`--`}
\n
\n {store.total_pages &&\n
store.changePage(page)} />\n }\n \n
\n
\n
\n }\n)\n","import React from 'react'\nimport {List, AutoSizer, CellMeasurer, CellMeasurerCache} from 'react-virtualized'\nimport Select, {components} from 'react-select'\n\nexport class VirtualizedMenuList extends React.PureComponent {\n constructor(props) {\n super(props)\n this.cache = new CellMeasurerCache({\n fixedWidth: true,\n defaultHeight: 35,\n })\n this.filter_val = \"\"\n }\n\n render() {\n const {options, children, maxHeight, getValue, selectProps} = this.props\n const rowCount = children.length || 0\n\n //gotta be a way to improve this. it's ok after the first couple of\n //characters search, but it's slow prior to that\n if(selectProps.inputValue !== this.filter_val) {\n this.filter_val = selectProps.inputValue\n this.cache.clearAll()\n }\n\n return (\n \n
\n
\n {({width, height}) => {\n return No selections available
}\n rowRenderer={\n ({index, parent, key, style}) =>\n \n {children[index]}
\n \n }/>\n }}\n
\n
\n
\n )\n }\n}\n\nconst VirtualizedSelect = props => (\n \n)\n\nexport default VirtualizedSelect\n","import React from 'react'\nimport ReactDOM from 'react-dom'\nimport {ProgramAuditLogStore} from './models'\nimport {IndexView} from './views'\n\n/*\n * Model/Store setup\n */\nconst store = new ProgramAuditLogStore(\n jsContext.program_id,\n)\n\nReactDOM.render(\n ,\n document.querySelector('#app_root')\n)\n","\nimport React from 'react'\n\nconst LoadingSpinner = ({children, isLoading, className, ...props}) => {\n const loading = (isLoading)?'loading':''\n return \n}\n\nexport default LoadingSpinner\n","import React from 'react'\n\nclass Expander extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n expanded: false,\n overflowing: false,\n }\n this.ref = React.createRef()\n }\n\n componentDidMount() {\n if(this.ref.current.scrollHeight > this.ref.current.clientHeight) {\n this.setState({overflowing: true})\n }\n }\n\n toggleExpanded(e) {\n e.preventDefault()\n this.setState({\n expanded: !this.state.expanded\n })\n }\n\n render() {\n return \n
\n {this.props.children}\n
\n {this.state.overflowing &&\n
\n }\n
\n }\n}\n\nexport default Expander\n","import React from 'react'\nimport ReactPaginate from 'react-paginate'\nimport { observer } from \"mobx-react\"\n\n/***\n Props:\n\n - pageCount: total number of pages\n - initialPage: which page should be highlighted as active initially\n - onPageChange: a function to receive the newly selected page\n*/\nconst Pagination = (props) => {\n return \n}\n\nexport default Pagination\n","import { observer } from \"mobx-react\"\nimport React from 'react';\nimport classNames from 'classnames';\n\n// TODO: \"size\" is no longer used\nconst ColumnComponent = ({className, size, ...props}) => {props.children} \n\n// TODO: this is redundant with ColumnComponent\nconst HeaderColumnComponent = ({className, size, ...props}) => {props.children} \n\nconst InnerRowComponent = ({className, ...props}) => {props.children} \n\n// TODO: this is redundant with InnerRowComponent\nconst HeaderRowComponent = ({className, ...props}) => {props.children} \n\n/***\n A wrapper for the rendering of the given row renderer, it takes and expando\n renderer used to render expanded content\n\n Props:\n - expanded: whether the expando content is shown or not\n - Expando: The content to render when the expando is shown\n*/\nconst RowComponent = observer(({className, expanded, Expando, ...props}) => {\n if(Expando) {\n const ObservedExpando = observer(Expando)\n return \n {props.children} \n {expanded && }\n \n } else {\n return \n {props.children} \n \n }\n})\nconst ExpandoWrapper = ({className, ...props}) => {props.children} \n\nconst RowList = observer(({data, Row, keyField, ...props}) => {\n const ObservedRow = observer(Row)\n return data.map(row_data => )\n})\n\n/*\n Props:\n\n - HeaderRow: a function to render the header row. it receives a component\n prop to render the header column and row\n\n - Row: a function used to render each row. it receives a component prop to\n render the row (see RowComponent), it receives the relevant data for that\n row as a prop: data\n\n - data: the dataset used to render the table, it must be an array\n\n - keyField: field to use for key on rows and expando checking\n\n */\nconst ManagementTable = observer(({HeaderRow, className, ...props}) => {\n const ObservedHeaderRow = observer(HeaderRow)\n return \n})\nexport default ManagementTable\n","import axios from 'axios';\n\nexport const api = axios.create({\n withCredentials: true,\n baseURL: '/api/',\n headers: {\n \"X-CSRFToken\": document.cookie.replace(/(?:(?:^|.*;\\s*)csrftoken\\s*\\=\\s*([^;]*).*$)|^.*$/, \"$1\")\n }\n});\n","import React from 'react'\nimport Select, {components} from 'react-select'\nimport {VirtualizedMenuList as MenuList} from './virtualized-react-select'\nimport {observer} from 'mobx-react'\n\nconst Option = props => {\n return (components.Option &&\n \n {\n //we can let the outer component manage state\n }}\n />\n \n {props.data.label}\n \n )\n}\n\nconst CheckboxedMultiSelect = observer(props => (\n \n))\n\nexport default CheckboxedMultiSelect\n","import {api} from '../../../api';\n\nexport const fetchProgramAuditLogWithFilter = (program_id, page) => api.get(`/tola_management/program/${program_id}/audit_log/`, {params: {page: page}}).then(response => {\n let data = response.data\n let total_results_count = data.count\n let current_results_count = data.results.length\n let total_pages = data.page_count\n\n return {\n logs: data.results,\n total_pages: total_pages,\n total_entries: total_results_count,\n next_page: data.next,\n prev_page: data.previous\n }\n})\n\nexport default {\n fetchProgramAuditLogWithFilter\n}\n","import { observable, computed, action, runInAction } from \"mobx\"\nimport api from './api'\n\nexport class ProgramAuditLogStore {\n @observable program_id = null\n @observable log_rows = []\n @observable fetching = false\n @observable current_page = 0\n @observable details_target = null\n\n @observable entries_count = 0\n @observable total_pages = 0\n @observable next_page = null\n @observable previous_page = null\n @observable current_page = 0\n\n constructor(program_id) {\n this.program_id = program_id\n this.fetchProgramAuditLog()\n }\n\n @action\n fetchProgramAuditLog() {\n this.fetching = true\n\n api.fetchProgramAuditLogWithFilter(this.program_id, this.current_page + 1).then(results => {\n runInAction(() => {\n this.fetching = false\n this.log_rows = results.logs\n this.entries_count = results.total_entries\n this.total_pages = results.total_pages\n this.next_page = results.next_page\n this.previous_page = results.previous_page\n })\n })\n }\n\n @action\n toggleDetailsTarget(row_id) {\n if(this.details_target == row_id) {\n this.details_target = null\n } else {\n this.details_target = row_id\n }\n }\n\n @action\n changePage(page) {\n if(page.selected != this.current_page) {\n this.current_page = page.selected\n this.fetchProgramAuditLog()\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAPA;AACA;AASA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAFA;AACA;AAGA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAHA;AACA;AAIA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AACA;AAQA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAFA;AACA;AAIA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AATA;AACA;AAWA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AACA;AATA;AAWA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AAAA;AAAA;AAGA;AACA;AACA;AACA;;;;;;;;;;;;;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAbA;AAeA;;;AAEA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;;;;AAtBA;AACA;AAwBA;AACA;AACA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAKA;AAAA;AACA;AAAA;AACA;AAAA;AAGA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAGA;AACA;AAAA;AAWA;AAAA;AAAA;AAOA;AAAA;AAEA;AAAA;AAAA;AA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","sourceRoot":""}
\ No newline at end of file
diff --git a/build/dev-dist/audit_log-8f3ec9b285211b3b3934.js.map b/build/dev-dist/audit_log-8f3ec9b285211b3b3934.js.map
deleted file mode 100644
index 8df91256..00000000
--- a/build/dev-dist/audit_log-8f3ec9b285211b3b3934.js.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"file":"audit_log-8f3ec9b285211b3b3934.js","sources":["webpack:///./js/pages/tola_management_pages/audit_log/views.js","webpack:///./js/components/virtualized-react-select.js","webpack:///./js/pages/tola_management_pages/audit_log/index.js","webpack:///./js/components/loading-spinner.js","webpack:///./js/components/expander.js","webpack:///./js/components/pagination.js","webpack:///./js/components/management-table.js","webpack:///./js/api.js","webpack:///./js/components/checkboxed-multi-select.js","webpack:///./js/pages/tola_management_pages/audit_log/api.js","webpack:///./js/pages/tola_management_pages/audit_log/models.js"],"sourcesContent":["import React from 'react';\nimport { observer } from \"mobx-react\"\nimport Select from 'react-select'\nimport classNames from 'classnames'\nimport ManagementTable from 'components/management-table'\nimport Pagination from 'components/pagination'\nimport CheckboxedMultiSelect from 'components/checkboxed-multi-select'\nimport Expander from 'components/expander'\n\nimport LoadingSpinner from 'components/loading-spinner'\n\nconst pretty_change_type = {\n indicator_changed: gettext('Indicator changed'),\n indicator_created: gettext('Indicator created'),\n indicator_deleted: gettext('Indicator deleted'),\n result_changed: gettext('Result changed'),\n result_created: gettext('Result created'),\n result_deleted: gettext('Result deleted'),\n program_dates_changed: gettext('Program Dates Changed')\n}\n\nconst map_pretty_change_type = change_type => pretty_change_type[change_type]\n\nconst units_of_measure_type = {\n 1: gettext(\"Number\"),\n 2: gettext(\"Percentage\")\n}\nconst map_unit_of_measure_type = id => units_of_measure_type[id]\n\nconst directions_of_change = {\n 1: gettext(\"N/A\"),\n 2: gettext(\"Increase (+)\"),\n 3: gettext(\"Decrease (-)\"),\n}\nconst map_direction_of_change = id => directions_of_change[id]\n\nconst result_changeset_name_map = {\n 'evidence_url': gettext('Evidence Url'),\n 'evidence_name': gettext('Evidence Name'),\n 'date': gettext('Date'),\n 'target': gettext('Target'),\n 'value': gettext('Value'),\n}\n\nconst ResultChangeset = ({data, name}) => {\n if(name == 'evidence_url') {\n return {result_changeset_name_map[name]}: {(data != 'N/A')?Link :data}
\n } else {\n return {result_changeset_name_map[name]}: {data}
\n }\n}\n\nconst program_dates_changset_name_map = {\n 'start_date': gettext('Start Date'),\n 'end_date': gettext('End Date')\n}\n\nconst ProgramDatesChangeset = ({data, name}) => {\n return {program_dates_changset_name_map[name]}: {data}
\n}\n\nconst indicator_changeset_name_map = {\n name: gettext('Name'),\n unit_of_measure: gettext('Unit of Measure'),\n unit_of_measure_type: gettext('Unit of Measure Type'),\n is_cumulative: gettext('Is Cumulative'),\n lop_target: gettext('LOP Target'),\n direction_of_change: gettext('Direction of Change'),\n rationale_for_target: gettext('Rationale for Target'),\n baseline_value: gettext('Baseline Value'),\n baseline_na: gettext('Baseline N/A'),\n}\n\nconst IndicatorChangeset = ({data, name}) => {\n const mapped_data = (() => {\n if (data == 'N/A') return data\n\n switch(name) {\n case 'unit_of_measure_type':\n return map_unit_of_measure_type(data)\n break\n case 'direction_of_change':\n return map_direction_of_change(data)\n break\n default:\n return data\n break\n }\n })()\n if(name == 'targets') {\n return \n
Targets
\n {Object.entries(data).map(([id, target]) => {\n return
{target.name}: {target.value}
\n })}\n
\n } else {\n return \n {indicator_changeset_name_map[name]}: {(mapped_data !== null && mapped_data !== undefined)?mapped_data.toString():'N/A'}\n
\n }\n}\n\nclass ChangesetEntry extends React.Component {\n renderType(type, data, name) {\n switch(type) {\n case 'indicator_changed':\n case 'indicator_created':\n case 'indicator_deleted':\n return \n break\n case 'result_changed':\n case 'result_created':\n case 'result_deleted':\n return \n break\n case 'program_dates_changed':\n return \n break\n }\n }\n\n render() {\n const {data, type, name} = this.props\n return this.renderType(type, data, name)\n }\n}\n\nexport const IndexView = observer(\n ({store}) => {\n return \n\n
\n
\n
\n \n \n \n {gettext(\"Date and Time\")} \n {gettext(\"No.\")} \n {gettext(\"Indicator\")} \n {gettext(\"User\")} \n {gettext(\"Organization\")} \n {gettext(\"Change Type\")} \n {gettext(\"Previous Entry\")} \n {gettext(\"New Entry\")} \n {gettext(\"Rationale\")} \n \n \n \n {store.log_rows.map(data => \n {data.date} \n {(data.indicator)?data.indicator.number:'N/A'} \n {(data.indicator)?data.indicator.name:'N/A'} \n {data.user} \n {data.organization} \n {map_pretty_change_type(data.change_type)} \n \n \n {data.diff_list.map(changeset => {\n return \n })}\n \n \n \n \n {data.diff_list.map(changeset => {\n return \n })}\n \n \n {data.rationale} \n )}\n \n
\n \n
\n
{store.entries_count?`${store.entries_count} ${gettext(\"entries\")}`:`--`}
\n
\n {store.total_pages &&\n
store.changePage(page)} />\n }\n \n
\n
\n
\n }\n)\n","import React from 'react'\nimport {List, AutoSizer, CellMeasurer, CellMeasurerCache} from 'react-virtualized'\nimport Select, {components} from 'react-select'\n\nexport class VirtualizedMenuList extends React.PureComponent {\n constructor(props) {\n super(props)\n this.cache = new CellMeasurerCache({\n fixedWidth: true,\n defaultHeight: 35,\n })\n this.filter_val = \"\"\n }\n\n render() {\n const {options, children, maxHeight, getValue, selectProps} = this.props\n const rowCount = children.length || 0\n\n //gotta be a way to improve this. it's ok after the first couple of\n //characters search, but it's slow prior to that\n if(selectProps.inputValue !== this.filter_val) {\n this.filter_val = selectProps.inputValue\n this.cache.clearAll()\n }\n\n return (\n \n
\n
\n {({width, height}) => {\n return No selections available
}\n rowRenderer={\n ({index, parent, key, style}) =>\n \n {children[index]}
\n \n }/>\n }}\n
\n
\n
\n )\n }\n}\n\nconst VirtualizedSelect = props => (\n \n)\n\nexport default VirtualizedSelect\n","import React from 'react'\nimport ReactDOM from 'react-dom'\nimport {ProgramAuditLogStore} from './models'\nimport {IndexView} from './views'\n\n/*\n * Model/Store setup\n */\nconst store = new ProgramAuditLogStore(\n jsContext.program_id,\n)\n\nReactDOM.render(\n ,\n document.querySelector('#app_root')\n)\n","\nimport React from 'react'\n\nconst LoadingSpinner = ({children, isLoading, className, ...props}) => {\n const loading = (isLoading)?'loading':''\n return \n}\n\nexport default LoadingSpinner\n","import React from 'react'\n\nclass Expander extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n expanded: false,\n overflowing: false,\n }\n this.ref = React.createRef()\n }\n\n componentDidMount() {\n if(this.ref.current.scrollHeight > this.ref.current.clientHeight) {\n this.setState({overflowing: true})\n }\n }\n\n toggleExpanded(e) {\n e.preventDefault()\n this.setState({\n expanded: !this.state.expanded\n })\n }\n\n render() {\n return \n
\n {this.props.children}\n
\n {this.state.overflowing &&\n
\n }\n
\n }\n}\n\nexport default Expander\n","import React from 'react'\nimport ReactPaginate from 'react-paginate'\nimport { observer } from \"mobx-react\"\n\n/***\n Props:\n\n - pageCount: total number of pages\n - initialPage: which page should be highlighted as active initially\n - onPageChange: a function to receive the newly selected page\n*/\nconst Pagination = (props) => {\n return \n}\n\nexport default Pagination\n","import { observer } from \"mobx-react\"\nimport React from 'react';\nimport classNames from 'classnames';\n\n// TODO: \"size\" is no longer used\nconst ColumnComponent = ({className, size, ...props}) => {props.children} \n\n// TODO: this is redundant with ColumnComponent\nconst HeaderColumnComponent = ({className, size, ...props}) => {props.children} \n\nconst InnerRowComponent = ({className, ...props}) => {props.children} \n\n// TODO: this is redundant with InnerRowComponent\nconst HeaderRowComponent = ({className, ...props}) => {props.children} \n\n/***\n A wrapper for the rendering of the given row renderer, it takes and expando\n renderer used to render expanded content\n\n Props:\n - expanded: whether the expando content is shown or not\n - Expando: The content to render when the expando is shown\n*/\nconst RowComponent = observer(({className, expanded, Expando, ...props}) => {\n if(Expando) {\n const ObservedExpando = observer(Expando)\n return \n {props.children} \n {expanded && }\n \n } else {\n return \n {props.children} \n \n }\n})\nconst ExpandoWrapper = ({className, ...props}) => {props.children} \n\nconst RowList = observer(({data, Row, keyField, ...props}) => {\n const ObservedRow = observer(Row)\n return data.map(row_data => )\n})\n\n/*\n Props:\n\n - HeaderRow: a function to render the header row. it receives a component\n prop to render the header column and row\n\n - Row: a function used to render each row. it receives a component prop to\n render the row (see RowComponent), it receives the relevant data for that\n row as a prop: data\n\n - data: the dataset used to render the table, it must be an array\n\n - keyField: field to use for key on rows and expando checking\n\n */\nconst ManagementTable = observer(({HeaderRow, className, ...props}) => {\n const ObservedHeaderRow = observer(HeaderRow)\n return \n})\nexport default ManagementTable\n","import axios from 'axios';\n\nexport const api = axios.create({\n withCredentials: true,\n baseURL: '/api/',\n headers: {\n \"X-CSRFToken\": document.cookie.replace(/(?:(?:^|.*;\\s*)csrftoken\\s*\\=\\s*([^;]*).*$)|^.*$/, \"$1\")\n }\n});\n","import React from 'react'\nimport Select, {components} from 'react-select'\nimport {VirtualizedMenuList as MenuList} from './virtualized-react-select'\nimport {observer} from 'mobx-react'\n\nconst Option = props => {\n return (components.Option &&\n \n {\n //we can let the outer component manage state\n }}\n />\n \n {props.data.label}\n \n )\n}\n\nconst CheckboxedMultiSelect = observer(props => (\n \n))\n\nexport default CheckboxedMultiSelect\n","import {api} from '../../../api';\n\nexport const fetchProgramAuditLogWithFilter = (program_id, page) => api.get(`/tola_management/program/${program_id}/audit_log/`, {params: {page: page}}).then(response => {\n let data = response.data\n let total_results_count = data.count\n let current_results_count = data.results.length\n let total_pages = data.page_count\n\n return {\n logs: data.results,\n total_pages: total_pages,\n total_entries: total_results_count,\n next_page: data.next,\n prev_page: data.previous\n }\n})\n\nexport default {\n fetchProgramAuditLogWithFilter\n}\n","import { observable, computed, action, runInAction } from \"mobx\"\nimport api from './api'\n\nexport class ProgramAuditLogStore {\n @observable program_id = null\n @observable log_rows = []\n @observable fetching = false\n @observable current_page = 0\n @observable details_target = null\n\n @observable entries_count = 0\n @observable total_pages = 0\n @observable next_page = null\n @observable previous_page = null\n @observable current_page = 0\n\n constructor(program_id) {\n this.program_id = program_id\n this.fetchProgramAuditLog()\n }\n\n @action\n fetchProgramAuditLog() {\n this.fetching = true\n\n api.fetchProgramAuditLogWithFilter(this.program_id, this.current_page + 1).then(results => {\n runInAction(() => {\n this.fetching = false\n this.log_rows = results.logs\n this.entries_count = results.total_entries\n this.total_pages = results.total_pages\n this.next_page = results.next_page\n this.previous_page = results.previous_page\n })\n })\n }\n\n @action\n toggleDetailsTarget(row_id) {\n if(this.details_target == row_id) {\n this.details_target = null\n } else {\n this.details_target = row_id\n }\n }\n\n @action\n changePage(page) {\n if(page.selected != this.current_page) {\n this.current_page = page.selected\n this.fetchProgramAuditLog()\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAPA;AACA;AASA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAFA;AACA;AAGA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAHA;AACA;AAIA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AALA;AACA;AAOA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAFA;AACA;AAIA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AATA;AACA;AAWA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AACA;AATA;AAWA;AACA;AAAA;AACA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAEA;AACA;AAGA;AACA;AACA;AACA;;;;;;;;;;;;;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAbA;AAeA;;;AAEA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;;;;AAtBA;AACA;AAwBA;AACA;AACA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAKA;AAAA;AAUA;AAAA;AAAA;AAOA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAGA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAGA;AAAA;AArBA;AA0BA;AAAA;AACA;AAAA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAHA;AASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/LA;AA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","sourceRoot":""}
\ No newline at end of file
diff --git a/build/dist/base-faf56600e8452e84ab36.css b/build/dev-dist/base-41e082a648aa1a38fbc4.css
similarity index 99%
rename from build/dist/base-faf56600e8452e84ab36.css
rename to build/dev-dist/base-41e082a648aa1a38fbc4.css
index c03173ff..3727cc58 100644
--- a/build/dist/base-faf56600e8452e84ab36.css
+++ b/build/dev-dist/base-41e082a648aa1a38fbc4.css
@@ -7768,6 +7768,9 @@ span[data-toggle="popover"]:hover {
.td--stretch {
width: 100%; }
+.td--half-stretch {
+ width: 50%; }
+
#nonfooter {
flex-grow: 1; }
@@ -8313,12 +8316,6 @@ span[data-toggle="popover"]:hover {
.mgmt-table__row--expanded > td {
padding: 30px; }
-#user-management-index-view .edit-user-history table .program-changeset-row,
-#program-management-index-view .edit-user-history table .program-changeset-row,
-#country-management-index-view .edit-user-history table .program-changeset-row {
- border: 1px solid #aaa;
- padding: 5px; }
-
.edit-user-programs .check-column {
text-align: center; }
@@ -8399,9 +8396,12 @@ span[data-toggle="popover"]:hover {
cursor: pointer;
width: 40px; }
-.expander {
+.changelog-entry__expanding {
overflow: hidden; }
+.changelog__entry__header.is-expanded {
+ background-color: #ebedf0; }
+
/* Safari */
@-webkit-keyframes spin {
0% {
@@ -8459,8 +8459,6 @@ table.admin-list__table {
vertical-align: top; }
table.admin-list__table th, table.admin-list__table td {
vertical-align: top; }
- table.admin-list__table .expand-section {
- width: 10%; }
.objective-form-buttons {
display: flex; }
@@ -9201,3 +9199,5 @@ a:hover {
/* Unsorted custom selectors */
+
+/*# sourceMappingURL=base-41e082a648aa1a38fbc4.css.map*/
\ No newline at end of file
diff --git a/build/dev-dist/base-fdebc32420e55b9873d8.js b/build/dev-dist/base-702c52ce47930ba15f84.js
similarity index 99%
rename from build/dev-dist/base-fdebc32420e55b9873d8.js
rename to build/dev-dist/base-702c52ce47930ba15f84.js
index ec335a13..4152006d 100644
--- a/build/dev-dist/base-fdebc32420e55b9873d8.js
+++ b/build/dev-dist/base-702c52ce47930ba15f84.js
@@ -482,4 +482,4 @@ window.create_nondestructive_changeset_notice = function () {
/***/ })
},[["YqHn","runtime","vendors"]]]);
-//# sourceMappingURL=base-fdebc32420e55b9873d8.js.map
\ No newline at end of file
+//# sourceMappingURL=base-702c52ce47930ba15f84.js.map
\ No newline at end of file
diff --git a/build/dev-dist/base-fdebc32420e55b9873d8.js.map b/build/dev-dist/base-702c52ce47930ba15f84.js.map
similarity index 99%
rename from build/dev-dist/base-fdebc32420e55b9873d8.js.map
rename to build/dev-dist/base-702c52ce47930ba15f84.js.map
index e5e1e1eb..2a2f2024 100644
--- a/build/dev-dist/base-fdebc32420e55b9873d8.js.map
+++ b/build/dev-dist/base-702c52ce47930ba15f84.js.map
@@ -1 +1 @@
-{"version":3,"file":"base-fdebc32420e55b9873d8.js","sources":["webpack:///./scss/tola.scss?c74b","webpack:///./js/base.js"],"sourcesContent":["// extracted by mini-css-extract-plugin","// Run the app's SCSS through webpack\nimport '@babel/polyfill'\nimport '../scss/tola.scss';\nimport 'react-virtualized/styles.css'\n\n\n/*\n * Moved legacy app.js code here - Contains global functions called by template code\n * along with global setup to be performed on every page\n *\n * If you decide to add a new function to this grab bag, and want to call it from Django\n * template code, make sure to add it to the `window` obj to make it globally accessible\n */\n\n\n\n/*\n * Global AJAX handlers for indicating a request in progress + error reporting\n */\n$( document )\n .ajaxStart( function() {\n $('#ajaxloading').show();\n })\n .ajaxStop( function() {\n $('#ajaxloading').hide();\n })\n .ajaxError(function( event, jqxhr, settings, thrownError ) {\n if (settings.suppressErrors === true) {\n //do nothing\n } else {\n if (jqxhr.readyState === 4) {\n // HTTP error (can be checked by XMLHttpRequest.status and XMLHttpRequest.statusText)\n // TODO: Give better error mssages based on HTTP status code\n let errorStr = `${jqxhr.status}: ${jqxhr.statusText}`;\n notifyError(js_context.strings.serverError, errorStr);\n }\n else if (jqxhr.readyState === 0) {\n // Network error (i.e. connection refused, access denied due to CORS, etc.)\n notifyError(js_context.strings.networkError, js_context.strings.networkErrorTryAgain);\n }\n else {\n // something weird is happening\n notifyError(js_context.strings.unknownNetworkError, jqxhr.statusText);\n }\n }\n });\n\nif (!Date.prototype.toISODate) {\n Date.prototype.toISODate = function() {\n return this.getFullYear() + '-' +\n ('0'+ (this.getMonth()+1)).slice(-2) + '-' +\n ('0'+ this.getDate()).slice(-2);\n }\n}\n\n\nfunction zeroPad(n, width) {\n n = n + '';\n return n.length >= width ? n : new Array(width - n.length + 1).join(0) + n;\n}\n\nfunction isDate(dateVal) {\n /*\n var pattern = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n var dateArray = dateVal.match(pattern);\n if (dateArray == null) return false;\n\n var currentYear = (new Date).getFullYear();\n var year = dateArray[1];\n var month = dateArray[2];\n var day = dateArray[3];\n if (year < 2010 || year > (currentYear+3)) return false;\n if (month < 1 || month > 12) return false;\n if (day < 1 || day > 31) return false;\n return new Date(dateVal) === 'Invalid Date' ? false : true;\n */\n var date = new Date(dateVal);\n if (date == 'Invalid Date') {\n return false;\n }\n var currentYear = (new Date).getFullYear();\n if (date.getFullYear() > currentYear + 100 || date.getFullYear() < 1980 ) {\n return false;\n }\n return true;\n}\nwindow.isDate = isDate;\n\nfunction formatDate(dateString, day=0) {\n // Returns an ISO formatted naive datestring\n // Use only to sanitize simplified date strings e.g. for hidden fields or data attributes\n // If you’re trying to format a date[string] for user display, you probably want something else\n if (dateString == null || dateString == undefined || dateString.length == 0 || dateString == 'undefined' || dateString == 'null' ) {\n return '';\n }\n try {\n var dateval = new Date(dateString);\n var tz = dateval.getTimezoneOffset();\n var hrs = dateval.getHours();\n if (hrs > 0) {\n // alert(\"offsetting timezone tz=\" + tz + \" hrs = \" + hrs);\n dateval.setMinutes(dateval.getMinutes() + tz);\n }\n var year = dateval.getFullYear()\n var month = zeroPad((dateval.getMonth() + 1), 2);\n var paddedDay = zeroPad((day == 0 ? dateval.getDate() : day), 2);\n var ret = year + '-' + month + '-' + paddedDay\n return ret;\n } catch (err) {\n console.log(err);\n try {\n var dateArray = dateString.split('-');\n var year = dateArray[0];\n var month = zeroPad(parseInt(dateArray[1]), 2);\n var paddedDay = zeroPad((day == 0 ? dateArray[2] : day), 2);\n var ret = year + '-' + month + '-' + paddedDay\n return ret\n }\n catch (err) {\n return dateString == (null ? '' : dateString);\n }\n }\n}\nwindow.formatDate = formatDate;\n\n// \"2017-01-01\" -> Date with local timezone (not UTC)\nfunction localDateFromISOStr(dateStr) {\n let dateInts = dateStr.split('-').map(function(x) {return parseInt(x)});\n return new Date(dateInts[0], dateInts[1]-1, dateInts[2]);\n}\nwindow.localDateFromISOStr = localDateFromISOStr;\n\n// Return Date() with local timezone at midnight\nfunction localdate() {\n let today = new Date();\n today.setHours(0,0,0,0);\n return today;\n}\nwindow.localdate = localdate;\n\nconst n = \"numeric\",\n s = \"short\",\n l = \"long\",\n d2 = \"2-digit\";\n\n\nconst DATE_MED = {\n year: n,\n month: s,\n day: n\n};\n\n// Date() -> \"Oct 2, 2018\" (localized)\n// JS equiv of the Django template filter: |date:\"MEDIUM_DATE_FORMAT\"\nfunction mediumDateFormatStr(date) {\n const languageCode = window.userLang; // set in base.html by Django\n return new Intl.DateTimeFormat(languageCode, DATE_MED).format(date);\n}\nwindow.mediumDateFormatStr = mediumDateFormatStr;\n\n\n$(function() {\n // Javascript to enable link to tab\n var hash = document.location.hash;\n if (hash) {\n $('.nav-tabs a[href=\"'+hash+'\"]').tab('show');\n }\n\n // Change hash for page-reload\n $('a[data-toggle=\"tab\"]').on('show.bs.tab', function (e) {\n window.location.hash = e.target.hash;\n });\n\n // Enable popovers\n $('[data-toggle=\"popover\"]').popover({\n html: true\n })\n $('[data-toggle=\"popover\"]').on('click', function(e){\n e.preventDefault();\n });\n});\n\n\n\n//App specific JavaScript\n$(function () {\n $('[data-toggle=\"tooltip\"]').tooltip()\n});\n\n//custom jquery to trigger date picker, info pop-over and print category text\n$(document).ready(function() {\n $('.datepicker').datepicker({ dateFormat: \"yy-mm-dd\" });\n});\n\n\n/*\n * Create and show a Bootstrap alert.\n */\nfunction createAlert (type, message, fade, whereToAppend) {\n if (whereToAppend == undefined ){\n whereToAppend = \"#messages\";\n }\n $(whereToAppend).append(\n $(\n \"\" +\n \"
× \" +\n \"
\" + message + \"
\" +\n \"
\"\n )\n );\n if (fade == true) {\n // Remove the alert after 5 seconds if the user does not close it.\n $(\".dynamic-alert\").delay(5000).fadeOut(\"slow\", function () { $(this).remove(); });\n }\n}\nwindow.createAlert = createAlert;\n\n\n// using jQuery\nfunction getCookie(name) {\n var cookieValue = null;\n if (document.cookie && document.cookie != '') {\n var cookies = document.cookie.split(';');\n for (var i = 0; i < cookies.length; i++) {\n var cookie = jQuery.trim(cookies[i]);\n // Does this cookie string begin with the name we want?\n if (cookie.substring(0, name.length + 1) == (name + '=')) {\n cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\n break;\n }\n }\n }\n return cookieValue;\n}\n\n\nfunction csrfSafeMethod(method) {\n // these HTTP methods do not require CSRF protection\n return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));\n}\n\n/*\n * Set the csrf header before sending the actual ajax request\n * while protecting csrf token from being sent to other domains\n */\n$.ajaxSetup({\n crossDomain: false, // obviates need for sameOrigin test\n beforeSend: function(xhr, settings) {\n if (!csrfSafeMethod(settings.type)) {\n xhr.setRequestHeader(\"X-CSRFToken\", getCookie('csrftoken'));\n }\n }\n});\n\n\n/* Configure PNotify global settings */\n/* Do so on document ready since lib is included after app.js */\n$(function() {\n PNotify.defaults.styling = 'bootstrap4'; // Bootstrap version 4\n PNotify.defaults.icons = 'fontawesome5'; // Font Awesome 5\n\n // Show close button and hide pin button\n PNotify.modules.Buttons.defaults.closerHover = false;\n PNotify.modules.Buttons.defaults.sticker = false;\n});\n\n\n/* Notifications */\n\nfunction notifyError(title, msg) {\n PNotify.alert({\n text: msg,\n title: title,\n hide: false,\n type: 'error',\n });\n}\nwindow.notifyError = notifyError;\n\n\n$(document).ready(function() {\n $(document).on('hidden.bs.modal', '.modal', function () {\n $('.modal:visible').length && $(document.body).addClass('modal-open');\n });\n});\n\n\n\n/*\n* Pop-up window for help docs and guidance on forms\n*/\n\nfunction newPopup(url, windowName) {\n return window.open(url,windowName,'height=768,width=1366,left=1200,top=10,titlebar=no,toolbar=no,menubar=no,location=no,directories=no,status=no');\n}\nwindow.newPopup = newPopup;\n\n// EXAMPLE: Form Help/Guidance \n\nconst DEFAULT_DESTRUCTIVE_MESSAGE = gettext(\"Your changes will be recorded in an audit log. Please record your rationale for future reference.\")\nconst DEFAULT_NONDESTRUCTIVE_MESSAGE = gettext('Your changes will be recorded in an audit log. Please record your rationale for future reference.')\n\nconst create_changeset_notice = ({\n message_text = DEFAULT_NONDESTRUCTIVE_MESSAGE,\n on_submit = () => {},\n on_cancel = () => {},\n confirm_text = 'Ok',\n cancel_text = 'Cancel',\n type = 'notice',\n inner = '',\n context = null\n} = {}) => {\n var notice = PNotify.alert({\n text: $(`
`).html(),\n textTrusted: true,\n icon: false,\n width: '350px',\n hide: false,\n type: type,\n addClass: 'program-page__rationale-form',\n stack: {\n 'overlayClose': true,\n 'dir1': 'right',\n 'dir2': 'up',\n 'firstpos1': 0,\n 'firstpos2': 0,\n 'context': context\n },\n modules: {\n Buttons: {\n closer: false,\n sticker: false\n },\n Confirm: {\n confirm: true,\n buttons: [\n {\n text: confirm_text,\n primary: true,\n addClass:(type == 'error')?'btn-danger':'',\n click: function (notice) {\n var close = true;\n var textarea = $(notice.refs.elem).find('textarea[name=\"rationale\"]')\n var rationale = textarea.val();\n textarea.parent().find('.invalid-feedback').remove();\n if(!rationale) {\n textarea.addClass('is-invalid');\n textarea.parent().append(`\n \n Results have been recorded. Rationale is required.\n
\n `);\n return false;\n } else {\n textarea.removeClass('is-invalid');\n }\n if(on_submit) {\n close = on_submit(rationale);\n if(close === undefined) {\n close = true;\n }\n }\n if(close) {\n notice.close();\n }\n }\n },\n {\n text: cancel_text,\n click: function (notice) {\n close = on_cancel()\n if(close === undefined) {\n close = true;\n }\n\n if(close) {\n notice.close();\n }\n }\n }\n ]\n }\n }\n })\n}\n\nwindow.create_destructive_changeset_notice = ({\n message_text = DEFAULT_DESTRUCTIVE_MESSAGE,\n on_submit = () => {},\n on_cancel = () => {},\n is_indicator = false,\n confirm_text = 'Ok',\n cancel_text = 'Cancel',\n context = null,\n no_preamble = false\n} = {}) => {\n if(!message_text) {message_text = DEFAULT_DESTRUCTIVE_MESSAGE}\n const preamble = (no_preamble)?'':`${gettext(\"This action cannot be undone.\")} `\n const inner = `\n \n
\n
${gettext(\"Warning\")} \n \n
\n \n
\n ${preamble}\n ${message_text}\n
\n
\n \n `;\n return create_changeset_notice({\n message_text: message_text,\n on_submit: on_submit,\n on_cancel: on_cancel,\n is_indicator: is_indicator,\n confirm_text: confirm_text,\n cancel_text: cancel_text,\n type: 'error',\n inner: inner,\n context: context\n })\n}\n\nwindow.create_nondestructive_changeset_notice = ({\n message_text = DEFAULT_NONDESTRUCTIVE_MESSAGE,\n on_submit = () => {},\n on_cancel = () => {},\n is_indicator = false,\n confirm_text = 'Ok',\n cancel_text = 'Cancel',\n context = null\n} = {}) => {\n if(!message_text) {message_text = DEFAULT_NONDESTRUCTIVE_MESSAGE}\n const inner = `\n \n
\n
${gettext(\"Share Your Rationale\")} \n \n
\n \n
\n ${message_text}\n
\n
\n \n `;\n return create_changeset_notice({\n message_text: message_text,\n on_submit: on_submit,\n on_cancel: on_cancel,\n is_indicator: is_indicator,\n confirm_text: confirm_text,\n cancel_text: cancel_text,\n type: 'notice',\n inner: inner,\n context: context\n })\n}\n"],"mappings":";;;;;;;;;AAAA;;;;;;;;;;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAGA;;;;;;;;AAUA;;;;AAGA;AAEA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;AAcA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AAHA;AAOA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AADA;AAGA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAGA;;;;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAOA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;;;;;;AAIA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AANA;AAUA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAJA;AAMA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAIA;;;;AAIA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AASA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAQA;AACA;AACA;AACA;AAFA;AAIA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AA7BA;AAgCA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAXA;AAlCA;AALA;AAhBA;AAwEA;AACA;AACA;AASA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAoBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AATA;AAWA;AACA;AACA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAmBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AATA;AAWA;;;;A","sourceRoot":""}
\ No newline at end of file
+{"version":3,"file":"base-702c52ce47930ba15f84.js","sources":["webpack:///./scss/tola.scss?c74b","webpack:///./js/base.js"],"sourcesContent":["// extracted by mini-css-extract-plugin","// Run the app's SCSS through webpack\nimport '@babel/polyfill'\nimport '../scss/tola.scss';\nimport 'react-virtualized/styles.css'\n\n\n/*\n * Moved legacy app.js code here - Contains global functions called by template code\n * along with global setup to be performed on every page\n *\n * If you decide to add a new function to this grab bag, and want to call it from Django\n * template code, make sure to add it to the `window` obj to make it globally accessible\n */\n\n\n\n/*\n * Global AJAX handlers for indicating a request in progress + error reporting\n */\n$( document )\n .ajaxStart( function() {\n $('#ajaxloading').show();\n })\n .ajaxStop( function() {\n $('#ajaxloading').hide();\n })\n .ajaxError(function( event, jqxhr, settings, thrownError ) {\n if (settings.suppressErrors === true) {\n //do nothing\n } else {\n if (jqxhr.readyState === 4) {\n // HTTP error (can be checked by XMLHttpRequest.status and XMLHttpRequest.statusText)\n // TODO: Give better error mssages based on HTTP status code\n let errorStr = `${jqxhr.status}: ${jqxhr.statusText}`;\n notifyError(js_context.strings.serverError, errorStr);\n }\n else if (jqxhr.readyState === 0) {\n // Network error (i.e. connection refused, access denied due to CORS, etc.)\n notifyError(js_context.strings.networkError, js_context.strings.networkErrorTryAgain);\n }\n else {\n // something weird is happening\n notifyError(js_context.strings.unknownNetworkError, jqxhr.statusText);\n }\n }\n });\n\nif (!Date.prototype.toISODate) {\n Date.prototype.toISODate = function() {\n return this.getFullYear() + '-' +\n ('0'+ (this.getMonth()+1)).slice(-2) + '-' +\n ('0'+ this.getDate()).slice(-2);\n }\n}\n\n\nfunction zeroPad(n, width) {\n n = n + '';\n return n.length >= width ? n : new Array(width - n.length + 1).join(0) + n;\n}\n\nfunction isDate(dateVal) {\n /*\n var pattern = /^(\\d{4})-(\\d{2})-(\\d{2})$/;\n var dateArray = dateVal.match(pattern);\n if (dateArray == null) return false;\n\n var currentYear = (new Date).getFullYear();\n var year = dateArray[1];\n var month = dateArray[2];\n var day = dateArray[3];\n if (year < 2010 || year > (currentYear+3)) return false;\n if (month < 1 || month > 12) return false;\n if (day < 1 || day > 31) return false;\n return new Date(dateVal) === 'Invalid Date' ? false : true;\n */\n var date = new Date(dateVal);\n if (date == 'Invalid Date') {\n return false;\n }\n var currentYear = (new Date).getFullYear();\n if (date.getFullYear() > currentYear + 100 || date.getFullYear() < 1980 ) {\n return false;\n }\n return true;\n}\nwindow.isDate = isDate;\n\nfunction formatDate(dateString, day=0) {\n // Returns an ISO formatted naive datestring\n // Use only to sanitize simplified date strings e.g. for hidden fields or data attributes\n // If you’re trying to format a date[string] for user display, you probably want something else\n if (dateString == null || dateString == undefined || dateString.length == 0 || dateString == 'undefined' || dateString == 'null' ) {\n return '';\n }\n try {\n var dateval = new Date(dateString);\n var tz = dateval.getTimezoneOffset();\n var hrs = dateval.getHours();\n if (hrs > 0) {\n // alert(\"offsetting timezone tz=\" + tz + \" hrs = \" + hrs);\n dateval.setMinutes(dateval.getMinutes() + tz);\n }\n var year = dateval.getFullYear()\n var month = zeroPad((dateval.getMonth() + 1), 2);\n var paddedDay = zeroPad((day == 0 ? dateval.getDate() : day), 2);\n var ret = year + '-' + month + '-' + paddedDay\n return ret;\n } catch (err) {\n console.log(err);\n try {\n var dateArray = dateString.split('-');\n var year = dateArray[0];\n var month = zeroPad(parseInt(dateArray[1]), 2);\n var paddedDay = zeroPad((day == 0 ? dateArray[2] : day), 2);\n var ret = year + '-' + month + '-' + paddedDay\n return ret\n }\n catch (err) {\n return dateString == (null ? '' : dateString);\n }\n }\n}\nwindow.formatDate = formatDate;\n\n// \"2017-01-01\" -> Date with local timezone (not UTC)\nfunction localDateFromISOStr(dateStr) {\n let dateInts = dateStr.split('-').map(function(x) {return parseInt(x)});\n return new Date(dateInts[0], dateInts[1]-1, dateInts[2]);\n}\nwindow.localDateFromISOStr = localDateFromISOStr;\n\n// Return Date() with local timezone at midnight\nfunction localdate() {\n let today = new Date();\n today.setHours(0,0,0,0);\n return today;\n}\nwindow.localdate = localdate;\n\nconst n = \"numeric\",\n s = \"short\",\n l = \"long\",\n d2 = \"2-digit\";\n\n\nconst DATE_MED = {\n year: n,\n month: s,\n day: n\n};\n\n// Date() -> \"Oct 2, 2018\" (localized)\n// JS equiv of the Django template filter: |date:\"MEDIUM_DATE_FORMAT\"\nfunction mediumDateFormatStr(date) {\n const languageCode = window.userLang; // set in base.html by Django\n return new Intl.DateTimeFormat(languageCode, DATE_MED).format(date);\n}\nwindow.mediumDateFormatStr = mediumDateFormatStr;\n\n\n$(function() {\n // Javascript to enable link to tab\n var hash = document.location.hash;\n if (hash) {\n $('.nav-tabs a[href=\"'+hash+'\"]').tab('show');\n }\n\n // Change hash for page-reload\n $('a[data-toggle=\"tab\"]').on('show.bs.tab', function (e) {\n window.location.hash = e.target.hash;\n });\n\n // Enable popovers\n $('[data-toggle=\"popover\"]').popover({\n html: true\n })\n $('[data-toggle=\"popover\"]').on('click', function(e){\n e.preventDefault();\n });\n});\n\n\n\n//App specific JavaScript\n$(function () {\n $('[data-toggle=\"tooltip\"]').tooltip()\n});\n\n//custom jquery to trigger date picker, info pop-over and print category text\n$(document).ready(function() {\n $('.datepicker').datepicker({ dateFormat: \"yy-mm-dd\" });\n});\n\n\n/*\n * Create and show a Bootstrap alert.\n */\nfunction createAlert (type, message, fade, whereToAppend) {\n if (whereToAppend == undefined ){\n whereToAppend = \"#messages\";\n }\n $(whereToAppend).append(\n $(\n \"\" +\n \"
× \" +\n \"
\" + message + \"
\" +\n \"
\"\n )\n );\n if (fade == true) {\n // Remove the alert after 5 seconds if the user does not close it.\n $(\".dynamic-alert\").delay(5000).fadeOut(\"slow\", function () { $(this).remove(); });\n }\n}\nwindow.createAlert = createAlert;\n\n\n// using jQuery\nfunction getCookie(name) {\n var cookieValue = null;\n if (document.cookie && document.cookie != '') {\n var cookies = document.cookie.split(';');\n for (var i = 0; i < cookies.length; i++) {\n var cookie = jQuery.trim(cookies[i]);\n // Does this cookie string begin with the name we want?\n if (cookie.substring(0, name.length + 1) == (name + '=')) {\n cookieValue = decodeURIComponent(cookie.substring(name.length + 1));\n break;\n }\n }\n }\n return cookieValue;\n}\n\n\nfunction csrfSafeMethod(method) {\n // these HTTP methods do not require CSRF protection\n return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));\n}\n\n/*\n * Set the csrf header before sending the actual ajax request\n * while protecting csrf token from being sent to other domains\n */\n$.ajaxSetup({\n crossDomain: false, // obviates need for sameOrigin test\n beforeSend: function(xhr, settings) {\n if (!csrfSafeMethod(settings.type)) {\n xhr.setRequestHeader(\"X-CSRFToken\", getCookie('csrftoken'));\n }\n }\n});\n\n\n/* Configure PNotify global settings */\n/* Do so on document ready since lib is included after app.js */\n$(function() {\n PNotify.defaults.styling = 'bootstrap4'; // Bootstrap version 4\n PNotify.defaults.icons = 'fontawesome5'; // Font Awesome 5\n\n // Show close button and hide pin button\n PNotify.modules.Buttons.defaults.closerHover = false;\n PNotify.modules.Buttons.defaults.sticker = false;\n});\n\n\n/* Notifications */\n\nfunction notifyError(title, msg) {\n PNotify.alert({\n text: msg,\n title: title,\n hide: false,\n type: 'error',\n });\n}\nwindow.notifyError = notifyError;\n\n\n$(document).ready(function() {\n $(document).on('hidden.bs.modal', '.modal', function () {\n $('.modal:visible').length && $(document.body).addClass('modal-open');\n });\n});\n\n\n\n/*\n* Pop-up window for help docs and guidance on forms\n*/\n\nfunction newPopup(url, windowName) {\n return window.open(url,windowName,'height=768,width=1366,left=1200,top=10,titlebar=no,toolbar=no,menubar=no,location=no,directories=no,status=no');\n}\nwindow.newPopup = newPopup;\n\n// EXAMPLE: Form Help/Guidance \n\nconst DEFAULT_DESTRUCTIVE_MESSAGE = gettext(\"Your changes will be recorded in an audit log. Please record your rationale for future reference.\")\nconst DEFAULT_NONDESTRUCTIVE_MESSAGE = gettext('Your changes will be recorded in an audit log. Please record your rationale for future reference.')\n\nconst create_changeset_notice = ({\n message_text = DEFAULT_NONDESTRUCTIVE_MESSAGE,\n on_submit = () => {},\n on_cancel = () => {},\n confirm_text = 'Ok',\n cancel_text = 'Cancel',\n type = 'notice',\n inner = '',\n context = null\n} = {}) => {\n var notice = PNotify.alert({\n text: $(`
`).html(),\n textTrusted: true,\n icon: false,\n width: '350px',\n hide: false,\n type: type,\n addClass: 'program-page__rationale-form',\n stack: {\n 'overlayClose': true,\n 'dir1': 'right',\n 'dir2': 'up',\n 'firstpos1': 0,\n 'firstpos2': 0,\n 'context': context\n },\n modules: {\n Buttons: {\n closer: false,\n sticker: false\n },\n Confirm: {\n confirm: true,\n buttons: [\n {\n text: confirm_text,\n primary: true,\n addClass:(type == 'error')?'btn-danger':'',\n click: function (notice) {\n var close = true;\n var textarea = $(notice.refs.elem).find('textarea[name=\"rationale\"]')\n var rationale = textarea.val();\n textarea.parent().find('.invalid-feedback').remove();\n if(!rationale) {\n textarea.addClass('is-invalid');\n textarea.parent().append(`\n \n Results have been recorded. Rationale is required.\n
\n `);\n return false;\n } else {\n textarea.removeClass('is-invalid');\n }\n if(on_submit) {\n close = on_submit(rationale);\n if(close === undefined) {\n close = true;\n }\n }\n if(close) {\n notice.close();\n }\n }\n },\n {\n text: cancel_text,\n click: function (notice) {\n close = on_cancel()\n if(close === undefined) {\n close = true;\n }\n\n if(close) {\n notice.close();\n }\n }\n }\n ]\n }\n }\n })\n}\n\nwindow.create_destructive_changeset_notice = ({\n message_text = DEFAULT_DESTRUCTIVE_MESSAGE,\n on_submit = () => {},\n on_cancel = () => {},\n is_indicator = false,\n confirm_text = 'Ok',\n cancel_text = 'Cancel',\n context = null,\n no_preamble = false\n} = {}) => {\n if(!message_text) {message_text = DEFAULT_DESTRUCTIVE_MESSAGE}\n const preamble = (no_preamble)?'':`${gettext(\"This action cannot be undone.\")} `\n const inner = `\n \n
\n
${gettext(\"Warning\")} \n \n
\n \n
\n ${preamble}\n ${message_text}\n
\n
\n \n `;\n return create_changeset_notice({\n message_text: message_text,\n on_submit: on_submit,\n on_cancel: on_cancel,\n is_indicator: is_indicator,\n confirm_text: confirm_text,\n cancel_text: cancel_text,\n type: 'error',\n inner: inner,\n context: context\n })\n}\n\nwindow.create_nondestructive_changeset_notice = ({\n message_text = DEFAULT_NONDESTRUCTIVE_MESSAGE,\n on_submit = () => {},\n on_cancel = () => {},\n is_indicator = false,\n confirm_text = 'Ok',\n cancel_text = 'Cancel',\n context = null\n} = {}) => {\n if(!message_text) {message_text = DEFAULT_NONDESTRUCTIVE_MESSAGE}\n const inner = `\n \n
\n
${gettext(\"Share Your Rationale\")} \n \n
\n \n
\n ${message_text}\n
\n
\n \n `;\n return create_changeset_notice({\n message_text: message_text,\n on_submit: on_submit,\n on_cancel: on_cancel,\n is_indicator: is_indicator,\n confirm_text: confirm_text,\n cancel_text: cancel_text,\n type: 'notice',\n inner: inner,\n context: context\n })\n}\n"],"mappings":";;;;;;;;;AAAA;;;;;;;;;;;;ACAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAGA;;;;;;;;AAUA;;;;AAGA;AAEA;AACA;AAEA;AACA;AAEA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;;AAcA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAMA;AACA;AACA;AACA;AAHA;AAOA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAGA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AADA;AAGA;AACA;AACA;AACA;AACA;AAIA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAGA;;;;AAGA;AACA;AACA;AACA;AACA;AAAA;AACA;AAOA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAEA;AACA;AACA;AACA;AAEA;;;;;;AAIA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AANA;AAUA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAEA;AACA;AAAA;AACA;AACA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAJA;AAMA;AACA;AAAA;AAGA;AACA;AACA;AACA;AACA;AAIA;;;;AAIA;AACA;AACA;AACA;AAAA;AACA;AAGA;AACA;AACA;AACA;AASA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAQA;AACA;AACA;AACA;AAFA;AAIA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AA7BA;AAgCA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAXA;AAlCA;AALA;AAhBA;AAwEA;AACA;AACA;AASA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAoBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AATA;AAWA;AACA;AACA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAmBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AATA;AAWA;;;;A","sourceRoot":""}
\ No newline at end of file
diff --git a/build/dev-dist/tola_management_organization-4c0e78fa1302d9fc5d80.js.map b/build/dev-dist/tola_management_organization-4c0e78fa1302d9fc5d80.js.map
deleted file mode 100644
index dd25df7c..00000000
--- a/build/dev-dist/tola_management_organization-4c0e78fa1302d9fc5d80.js.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"file":"tola_management_organization-4c0e78fa1302d9fc5d80.js","sources":["webpack:///./js/pages/tola_management_pages/organization/models.js","webpack:///./js/components/virtualized-react-select.js","webpack:///./js/components/loading-spinner.js","webpack:///./js/pages/tola_management_pages/organization/views.js","webpack:///./js/components/expander.js","webpack:///./js/components/pagination.js","webpack:///./js/pages/tola_management_pages/organization/components/organization_editor.js","webpack:///./js/pages/tola_management_pages/organization/components/edit_organization_history.js","webpack:///./js/components/management-table.js","webpack:///./js/api.js","webpack:///./js/components/checkboxed-multi-select.js","webpack:///./js/pages/tola_management_pages/organization/index.js","webpack:///./js/components/folding-sidebar.js","webpack:///./js/pages/tola_management_pages/organization/components/edit_organization_profile.js","webpack:///./js/pages/tola_management_pages/organization/api.js"],"sourcesContent":["import { observable, computed, action, runInAction } from \"mobx\";\nimport api from './api';\n\nconst default_organization = {\n id: null ,\n is_active: false,\n mode_of_contact: \"\",\n name: \"\",\n organization_url: null,\n primary_address: \"\",\n primary_contact_email: \"\",\n primary_contact_name: \"\",\n primary_contact_phone: \"\",\n sectors: [],\n}\n\nexport class OrganizationStore {\n @observable organizations = {}\n @observable organizations_listing = []\n @observable organizations_count = 0\n @observable total_pagees = 0\n @observable fetching = false\n @observable fetching_editing_target = false\n @observable current_page = 0\n @observable saving = false\n\n @observable bulk_targets = new Map()\n @observable bulk_targets_all = false\n\n available_programs = {}\n available_organizations = {}\n available_sectors = {}\n available_countries = {}\n program_selections = []\n organization_selections = []\n sector_selections = []\n country_selections = []\n\n @observable editing_target = null\n @observable editing_target_data = {...default_organization}\n @observable editing_target_history = []\n @observable editing_errors = {}\n\n @observable filters = {\n countries: [],\n organizations: [],\n programs: [],\n sectors: [],\n organization_status: '',\n }\n\n organization_status_options = [\n {value: 1, label: gettext('Active')},\n {value: 0, label: gettext('Inactive')}\n ]\n\n constructor(programs, organizations, sectors, countries, country_filter, program_filter) {\n this.available_programs = programs\n this.available_organizations = organizations\n this.available_sectors = sectors\n this.available_countries = countries\n this.organization_selections = Object.entries(organizations).map(([id, org]) => ({value: org.id, label: org.name}))\n this.program_selections = Object.entries(programs).map(([id, program]) => ({value: program.id, label: program.name}))\n this.sector_selections = Object.entries(sectors).map(([id, sector]) => ({value: sector.id, label: sector.name}))\n this.country_selections = Object.entries(countries).map(([id, country]) => ({value: country.id, label: country.name}))\n this.filters.countries = country_filter.map(id => this.available_countries[id]).map(country => ({label: country.name, value: country.id}))\n this.filters.programs = program_filter.filter(id => programs[id]).map(id => ({label: programs[id].name, value: id}))\n this.fetchOrganizations()\n }\n\n marshalFilters(filters) {\n return Object.entries(filters).reduce((xs, x) => {\n if(Array.isArray(x[1])) {\n xs[x[0]] = x[1].map(x => x.value)\n } else {\n xs[x[0]] = x[1].value\n }\n return xs\n }, {})\n }\n\n updateLocalOrganization(id, applied_data, aggregates) {\n this.organizations[id] = {\n id: id,\n name: applied_data.name,\n program_count: aggregates.program_count,\n user_count: aggregates.user_count,\n is_active: applied_data.is_active\n }\n }\n\n onSaveErrorHandler() {\n PNotify.error({text: gettext('Saving Failed'), delay: 5000});\n }\n\n onSaveSuccessHandler() {\n PNotify.success({text: gettext('Successfully Saved'), delay: 5000})\n }\n\n @action\n fetchOrganizations() {\n this.fetching = true\n\n api.fetchOrganizationsWithFilter(this.current_page + 1, this.marshalFilters(this.filters)).then(results => {\n runInAction(() => {\n this.fetching = false\n this.organizations = results.organizations.reduce((xs, x) => {\n xs[x.id] = x\n return xs\n }, {})\n this.organizations_listing = results.organizations.map(o => o.id)\n this.organizations_count = results.total_organizations\n this.total_pages = results.total_pages\n this.bulk_targets = new Map(Object.entries(this.organizations).map(([_, organization]) => [organization.id, false]))\n })\n })\n }\n\n @action\n applyFilters() {\n this.current_page = 0\n this.fetchOrganizations()\n }\n\n @action\n createOrganization() {\n const new_organization = {\n id: \"new\",\n name: \"\",\n program_count: 0,\n user_count: 0,\n is_active: false\n }\n if(this.editing_target !== \"new\") {\n this.organizations_listing.unshift(\"new\")\n }\n\n this.editing_errors = {}\n this.organizations[\"new\"] = new_organization\n this.editing_target = new_organization.id\n this.editing_target_data = {...default_organization}\n }\n\n @action\n updateOrganizationProfile(id, new_data) {\n this.saving = true\n api.updateOrganization(id, new_data).then(updated_data => api.fetchOrganizationAggregates(id).then(aggregates => {\n runInAction(() => {\n this.saving = false\n this.updateLocalOrganization(id, updated_data, aggregates)\n this.editing_target = null\n this.editing_target_data = {...default_organization}\n })\n this.onSaveSuccessHandler()\n })).catch((error) => {\n runInAction(() => {\n this.saving = false\n this.editing_errors = error.response.data\n })\n this.onSaveErrorHandler()\n })\n }\n\n @action\n saveNewOrganization(new_data) {\n this.saving = true\n new_data.is_active = true;\n api.createOrganization(new_data).then(result => {\n runInAction(() => {\n this.saving = false\n this.updateLocalOrganization(result.id, result, {program_count: 0, user_count: 0})\n this.organizations_listing.shift()\n delete this.organizations[\"new\"]\n this.organizations_listing.unshift(result.id)\n this.editing_target = null\n this.editing_target_data = {...default_organization}\n this.bulk_targets = new Map(Object.entries(this.organizations).map(([_, organization]) => [organization.id, false]))\n })\n this.onSaveSuccessHandler()\n }).catch(error => {\n runInAction(() => {\n this.saving = false\n this.editing_errors = error.response.data\n })\n this.onSaveErrorHandler()\n })\n }\n\n @action\n saveNewOrganizationAndAddAnother(new_data) {\n this.saving = true\n new_data.is_active = true;\n api.createOrganization(new_data).then(result => {\n runInAction(() => {\n this.saving = false\n this.updateLocalOrganization(result.id, result, {program_count: 0, user_count: 0})\n this.organizations_listing.shift()\n delete this.organizations[\"new\"]\n this.organizations_listing.unshift(result.id)\n this.editing_target = null\n this.editing_target_data = {...default_organization}\n this.bulk_targets = new Map(Object.entries(this.organizations).map(([_, organization]) => [organization.id, false]))\n })\n this.onSaveSuccessHandler()\n }).catch(error => {\n runInAction(() => {\n this.saving = false\n this.editing_errors = error.response.data\n })\n this.onSaveErrorHandler()\n })\n }\n\n @action\n changeSectorFilter(sectors) {\n this.filters.sectors = sectors\n }\n\n @action\n changeCountryFilter(countries) {\n this.filters.countries = countries\n }\n\n @action\n changeProgramFilter(programs) {\n this.filters.programs = programs\n }\n\n @action\n changeOrganizationFilter(organizations) {\n this.filters.organizations = organizations\n }\n\n @action\n changeOrganizationStatusFilter(status) {\n this.filters.organization_status = status\n }\n\n @action\n changePage(page) {\n if(this.current_page != page.selected) {\n this.current_page = page.selected\n this.fetchOrganizations()\n }\n }\n\n @action\n toggleBulkTargetsAll() {\n this.bulk_targets_all = !this.bulk_targets_all;\n if(this.bulk_targets_all) {\n this.bulk_targets.forEach((val, key, map) => {\n map.set(key, true)\n })\n } else {\n this.bulk_targets.forEach((val, key, map) => {\n map.set(key, false)\n })\n }\n }\n\n @action\n toggleEditingTarget(organization_id) {\n this.editing_target_data = {...default_organization}\n this.editing_errors = {}\n\n if(this.editing_target == \"new\") {\n this.organizations_listing.shift()\n }\n\n if(this.editing_target == organization_id) {\n this.editing_target = false\n } else {\n this.editing_target = organization_id\n this.fetching_editing_target = true\n if(!(this.editing_target == 'new')) {\n Promise.all([api.fetchOrganization(organization_id), api.fetchOrganizationHistory(organization_id)]).then(([organization, history]) => {\n runInAction(() => {\n this.fetching_editing_target = false\n this.editing_target_data = organization\n this.editing_target_history = history\n })\n })\n }\n }\n }\n\n @action\n toggleBulkTarget(target_id) {\n this.bulk_targets.set(target_id, !this.bulk_targets.get(target_id))\n }\n\n @action\n clearFilters() {\n this.filters = {\n countries: [],\n organizations: [],\n programs: [],\n sectors: [],\n organization_status: '',\n }\n }\n}\n","import React from 'react'\nimport {List, AutoSizer, CellMeasurer, CellMeasurerCache} from 'react-virtualized'\nimport Select, {components} from 'react-select'\n\nexport class VirtualizedMenuList extends React.PureComponent {\n constructor(props) {\n super(props)\n this.cache = new CellMeasurerCache({\n fixedWidth: true,\n defaultHeight: 35,\n })\n this.filter_val = \"\"\n }\n\n render() {\n const {options, children, maxHeight, getValue, selectProps} = this.props\n const rowCount = children.length || 0\n\n //gotta be a way to improve this. it's ok after the first couple of\n //characters search, but it's slow prior to that\n if(selectProps.inputValue !== this.filter_val) {\n this.filter_val = selectProps.inputValue\n this.cache.clearAll()\n }\n\n return (\n \n
\n
\n {({width, height}) => {\n return No selections available
}\n rowRenderer={\n ({index, parent, key, style}) =>\n \n {children[index]}
\n \n }/>\n }}\n
\n
\n
\n )\n }\n}\n\nconst VirtualizedSelect = props => (\n \n)\n\nexport default VirtualizedSelect\n","\nimport React from 'react'\n\nconst LoadingSpinner = ({children, isLoading, className, ...props}) => {\n const loading = (isLoading)?'loading':''\n return \n}\n\nexport default LoadingSpinner\n","import React from 'react';\nimport { observer } from \"mobx-react\"\nimport Select from 'react-select'\nimport ManagementTable from 'components/management-table'\nimport Pagination from 'components/pagination'\nimport CheckboxedMultiSelect from 'components/checkboxed-multi-select'\n\nimport OrganizationEditor from './components/organization_editor'\nimport EditOrganizationProfile from './components/edit_organization_profile'\nimport EditOrganizationHistory from './components/edit_organization_history'\n\nimport LoadingSpinner from 'components/loading-spinner'\nimport FoldingSidebar from 'components/folding-sidebar'\n\nconst CountryFilter = observer(({store, selections}) => {\n return \n {gettext(\"Countries\")} \n store.changeCountryFilter(e)}\n placeholder={gettext(\"None Selected\")}\n id=\"countries_permitted_filter\" />\n
\n})\n\nconst ProgramFilter = observer(({store, selections}) => {\n return \n {gettext(\"Programs\")} \n store.changeProgramFilter(e)}\n placeholder={gettext(\"None Selected\")}\n id=\"programs_filter\" />\n
\n})\n\nconst OrganizationFilter = observer(({store, selections}) => {\n return \n {gettext(\"Organizations\")} \n store.changeOrganizationFilter(e)}\n placeholder={gettext(\"None Selected\")}\n id=\"organization_filter\" />\n
\n})\n\nconst SectorFilter = observer(({store, selections}) => {\n return \n {gettext(\"Sectors\")} \n store.changeSectorFilter(e)}\n placeholder={gettext(\"None Selected\")}\n id=\"sector_filter\" />\n
\n})\n\nexport const IndexView = observer(\n ({store}) => {\n return \n
\n \n
\n
\n
\n
\n
\n {gettext(\"Status\")} \n store.changeOrganizationStatusFilter(e)}\n placeholder={gettext(\"None Selected\")}\n id=\"status_filter\" />\n
\n
\n store.applyFilters()}>{gettext(\"Apply\")} \n store.clearFilters()}>{gettext(\"Reset\")} \n
\n
\n \n
\n
\n
\n \n
store.organizations[id])}\n keyField=\"id\"\n HeaderRow={({Col, Row}) =>\n \n \n \n {gettext(\"Organization\")}\n {gettext(\"Programs\")}\n {gettext(\"Users\")}\n {gettext(\"Status\")}\n
\n }\n Row={({Col, Row, data}) =>\n \n \n \n \n store.updateOrganizationProfile(data.id, new_organization_data)}\n onSaveNew={(new_organization_data) => store.saveNewOrganization(new_organization_data)}\n onSaveNewAndAddAnother={(new_organization_data) => store.saveNewOrganizationAndAddAnother(new_organization_data)} />\n \n )}\n HistorySection={observer(() =>\n \n store.updateOrganizationProfile(data.id, new_organization_data)}/>\n \n )}\n />\n \n }>\n \n \n \n store.toggleEditingTarget(data.id)} >\n \n {data.name || \"---\"}\n
\n \n \n \n \n {data.program_count} {gettext(\"programs\")}\n \n \n \n \n \n {data.user_count} {gettext(\"users\")}\n \n \n {data.is_active?'Active':'Inactive'}\n
\n }\n />\n \n \n
\n
{store.organizations_count?`${store.organizations_count} ${gettext(\"organizations\")}`:`--`}
\n
\n {store.total_pages &&\n
store.changePage(page)} />\n }\n \n
\n
\n
\n }\n)\n","import React from 'react'\n\nclass Expander extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n expanded: false,\n overflowing: false,\n }\n this.ref = React.createRef()\n }\n\n componentDidMount() {\n if(this.ref.current.scrollHeight > this.ref.current.clientHeight) {\n this.setState({overflowing: true})\n }\n }\n\n toggleExpanded(e) {\n e.preventDefault()\n this.setState({\n expanded: !this.state.expanded\n })\n }\n\n render() {\n return \n
\n {this.props.children}\n
\n {this.state.overflowing &&\n
\n }\n
\n }\n}\n\nexport default Expander\n","import React from 'react'\nimport ReactPaginate from 'react-paginate'\nimport { observer } from \"mobx-react\"\n\n/***\n Props:\n\n - pageCount: total number of pages\n - initialPage: which page should be highlighted as active initially\n - onPageChange: a function to receive the newly selected page\n*/\nconst Pagination = (props) => {\n return \n}\n\nexport default Pagination\n","import React from 'react'\nimport { observer } from \"mobx-react\"\n\n@observer\nexport default class OrganizationEditor extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n active_page: 'profile'\n }\n }\n\n updateActivePage(new_page) {\n if(!this.props.new) {\n this.setState({active_page: new_page})\n }\n }\n\n render() {\n const {ProfileSection, HistorySection} = this.props\n\n const profile_active_class = (this.state.active_page == 'profile')?'active':''\n const history_active_class = (this.state.active_page == 'status_and_history')?'active':''\n const new_class = (this.props.new)?'disabled':''\n\n return (\n \n
\n
\n {this.state.active_page == 'profile' &&\n
\n }\n\n {this.state.active_page == 'status_and_history' &&\n
\n }\n
\n
\n )\n }\n}\n","import React from 'react'\nimport { observer } from \"mobx-react\"\nimport Select from 'react-select'\nimport {AutoSizer, Table, Column, CellMeasurer, CellMeasurerCache} from 'react-virtualized'\nimport Expander from 'components/expander'\n\nconst status_options = [\n {value: true, label: gettext('Active')},\n {value: false, label: gettext('Inactive')}\n]\n\nconst ChangesetEntry = ({name, type, data}) => {\n return {name} : {(data != undefined && data != null)?data.toString():'N/A'}
\n}\n\nexport default class EditOrganizationHistory extends React.Component {\n\n constructor(props) {\n super(props)\n const data = {\n ...props.organizationData,\n is_active: status_options.find(op => op.value == props.organizationData.is_active)\n }\n this.state = {\n initial_data: data,\n data: {...data}\n }\n }\n\n onChange(new_value) {\n this.state.data.is_active = new_value\n\n this.setState({\n data: this.state.data\n })\n }\n\n onReset() {\n this.setState({\n data: this.state.initial_data\n })\n }\n\n save(e) {\n e.preventDefault()\n this.props.onSave({\n ...this.state.data,\n is_active: this.state.data.is_active.value,\n sectors: this.state.data.sectors.map(sector => sector.id)\n })\n }\n\n render() {\n return \n
{this.state.data.name ? this.state.data.name+\": \": \"\"}{gettext(\"Status and history\")} \n
\n this.onChange(new_value)} />\n
\n
\n this.save(e)}>{gettext(\"Save Changes\")} \n this.onReset()}>{gettext(\"Reset\")} \n
\n
\n \n \n {gettext(\"Date\")} \n {gettext(\"Admin User\")} \n {gettext(\"Change Type\")} \n {gettext(\"Previous Entry\")} \n {gettext(\"New Entry\")} \n \n \n \n {this.props.organizationHistoryData.map(entry => \n {entry.date} \n {entry.admin_user} \n {entry.change_type} \n \n \n {entry.diff_list.map(changeset => {\n return \n })}\n \n \n \n \n {entry.diff_list.map(changeset => {\n return \n })}\n \n \n )}\n \n
\n
\n }\n}\n","import { observer } from \"mobx-react\"\nimport React from 'react';\nimport classNames from 'classnames';\n\n// TODO: \"size\" is no longer used\nconst ColumnComponent = ({className, size, ...props}) => {props.children} \n\n// TODO: this is redundant with ColumnComponent\nconst HeaderColumnComponent = ({className, size, ...props}) => {props.children} \n\nconst InnerRowComponent = ({className, ...props}) => {props.children} \n\n// TODO: this is redundant with InnerRowComponent\nconst HeaderRowComponent = ({className, ...props}) => {props.children} \n\n/***\n A wrapper for the rendering of the given row renderer, it takes and expando\n renderer used to render expanded content\n\n Props:\n - expanded: whether the expando content is shown or not\n - Expando: The content to render when the expando is shown\n*/\nconst RowComponent = observer(({className, expanded, Expando, ...props}) => {\n if(Expando) {\n const ObservedExpando = observer(Expando)\n return \n {props.children} \n {expanded && }\n \n } else {\n return \n {props.children} \n \n }\n})\nconst ExpandoWrapper = ({className, ...props}) => {props.children} \n\nconst RowList = observer(({data, Row, keyField, ...props}) => {\n const ObservedRow = observer(Row)\n return data.map(row_data => )\n})\n\n/*\n Props:\n\n - HeaderRow: a function to render the header row. it receives a component\n prop to render the header column and row\n\n - Row: a function used to render each row. it receives a component prop to\n render the row (see RowComponent), it receives the relevant data for that\n row as a prop: data\n\n - data: the dataset used to render the table, it must be an array\n\n - keyField: field to use for key on rows and expando checking\n\n */\nconst ManagementTable = observer(({HeaderRow, className, ...props}) => {\n const ObservedHeaderRow = observer(HeaderRow)\n return \n})\nexport default ManagementTable\n","import axios from 'axios';\n\nexport const api = axios.create({\n withCredentials: true,\n baseURL: '/api/',\n headers: {\n \"X-CSRFToken\": document.cookie.replace(/(?:(?:^|.*;\\s*)csrftoken\\s*\\=\\s*([^;]*).*$)|^.*$/, \"$1\")\n }\n});\n","import React from 'react'\nimport Select, {components} from 'react-select'\nimport {VirtualizedMenuList as MenuList} from './virtualized-react-select'\nimport {observer} from 'mobx-react'\n\nconst Option = props => {\n return (components.Option &&\n \n {\n //we can let the outer component manage state\n }}\n />\n \n {props.data.label}\n \n )\n}\n\nconst CheckboxedMultiSelect = observer(props => (\n \n))\n\nexport default CheckboxedMultiSelect\n","import React from 'react';\nimport ReactDOM from 'react-dom';\nimport {OrganizationStore} from './models';\nimport {IndexView} from './views';\n\n/*\n * Model/Store setup\n */\nconst store = new OrganizationStore(\n jsContext.programs,\n jsContext.organizations,\n jsContext.sectors,\n jsContext.countries,\n jsContext.country_filter,\n jsContext.program_filter,\n)\n\nReactDOM.render(\n ,\n document.querySelector('#app_root')\n)\n","import React from 'react'\n\nclass Expander extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n folded: false,\n }\n }\n\n toggleFolded() {\n this.setState({\n folded: !this.state.folded\n })\n }\n\n render() {\n const {className, ...props} = this.props\n const icon = (this.state.folded)?\"fa-chevron-right\":\"fa-chevron-left\"\n return \n {!this.state.folded &&\n
{this.props.children} \n }\n\n
this.toggleFolded()}>\n \n
\n
\n }\n}\n\nexport default Expander\n","import React from 'react'\nimport CheckboxedMultiSelect from 'components/checkboxed-multi-select'\nimport { observer } from \"mobx-react\"\n\n@observer\nexport default class EditOrganizationProfile extends React.Component {\n constructor(props) {\n super(props)\n const o = props.organizationData\n const data = {\n ...o,\n sectors: o.sectors.map(sector => ({value: sector.id, label: sector.sector}))\n }\n\n this.state = {\n initial_data: data,\n managed_data: {...data}\n }\n }\n\n save(e) {\n e.preventDefault()\n this.props.onSave({...this.state.managed_data, sectors: this.state.managed_data.sectors.map(sector => sector.value)})\n }\n\n saveNew(e) {\n e.preventDefault()\n this.props.onSaveNew({...this.state.managed_data, sectors: this.state.managed_data.sectors.map(sector => sector.value)})\n }\n\n saveNewAndAddAnother(e) {\n e.preventDefault()\n this.props.onSaveNewAndAddAnother({...this.state.managed_data, sectors: this.state.managed_data.sectors.map(sector => sector.value)})\n }\n\n resetForm() {\n this.setState({\n managed_data: this.state.initial_data\n })\n }\n\n updateName(new_name) {\n let new_data = this.state.managed_data\n new_data.name = new_name\n this.setState({\n managed_data: new_data\n })\n }\n\n updateSectors(new_sectors) {\n let new_data = this.state.managed_data\n new_data.sectors = new_sectors\n this.setState({\n managed_data: new_data\n })\n }\n\n updatePrimaryAddress(new_address) {\n let new_data = this.state.managed_data\n new_data.primary_address = new_address\n this.setState({\n managed_data: new_data\n })\n }\n\n updatePrimaryContactName(new_name) {\n let new_data = this.state.managed_data\n new_data.primary_contact_name = new_name\n this.setState({\n managed_data: new_data\n })\n }\n\n updatePrimaryContactEmail(new_email) {\n let new_data = this.state.managed_data\n new_data.primary_contact_email = new_email\n this.setState({\n managed_data: new_data\n })\n }\n\n updatePrimaryContactPhone(new_phone) {\n let new_data = this.state.managed_data\n new_data.primary_contact_phone = new_phone\n this.setState({\n managed_data: new_data\n })\n }\n\n updateModeOfContact(new_mode_of_contact) {\n let new_data = this.state.managed_data\n new_data.mode_of_contact = new_mode_of_contact\n this.setState({\n managed_data: new_data\n })\n }\n\n render() {\n let od = this.state.managed_data\n let errors = this.props.errors\n let error_classes = {\n name: (errors.name)?'is-invalid':'',\n primary_address: (errors.primary_address)?'is-invalid':'',\n primary_contact_name: (errors.primary_contact_name)?'is-invalid':'',\n primary_contact_email: (errors.primary_contact_email)?'is-invalid':'',\n primary_contact_phone: (errors.primary_contact_phone)?'is-invalid':'',\n }\n return (\n \n
{od.name ? od.name+\": \": \"\"}{gettext(\"Profile\")} \n
\n
\n )\n }\n}\n","import {api} from '../../../api';\n\nexport const fetchOrganizationsWithFilter = (page, filters) => api.get('/tola_management/organization/', {params: {page: page, ...filters}}).then(response => {\n let data = response.data\n let total_results_count = data.count\n let current_results_count = data.results.length\n let total_pages = data.page_count\n\n return {\n organizations: data.results,\n total_pages: total_pages,\n total_organizations: total_results_count,\n next_page: data.next,\n prev_page: data.previous\n }\n})\n\nexport const fetchOrganization = (id) => api.get(`/tola_management/organization/${id}/`).then(response => response.data)\n\nexport const updateOrganization = (id, new_data) => api.put(`/tola_management/organization/${id}/`, {\n ...new_data,\n sectors: new_data.sectors.map(sector => ({id: sector}))\n}).then(response => response.data)\n\nexport const createOrganization = (new_data) => api.post(`/tola_management/organization/`, {\n ...new_data,\n sectors: new_data.sectors.map(sector => ({id: sector}))\n}).then(response => response.data)\n\nexport const fetchOrganizationAggregates = id => api.get(`/tola_management/organization/${id}/aggregate_data/`).then(response => response.data)\n\nexport const fetchOrganizationHistory = id => api.get(`/tola_management/organization/${id}/history/`).then(response => response.data)\n\nexport default {\n fetchOrganizationsWithFilter,\n fetchOrganization,\n fetchOrganizationHistory,\n fetchOrganizationAggregates,\n updateOrganization,\n createOrganization,\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAVA;AAaA;AAAA;AAAA;AAwCA;AAAA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AAJA;AAAA;AAAA;AACA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AArDA;AAAA;AAAA;AAuDA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AA/DA;AAAA;AAAA;AAkEA;AACA;AACA;AACA;AACA;AACA;AALA;AAOA;AAzEA;AAAA;AAAA;AA4EA;AAAA;AAAA;AAAA;AACA;AA7EA;AAAA;AAAA;AAgFA;AAAA;AAAA;AAAA;AACA;AAjFA;AAAA;AAAA;AAoFA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AACA;AACA;AACA;AApGA;AAAA;AAAA;AAwGA;AACA;AACA;AA1GA;AAAA;AAAA;AA8GA;AACA;AACA;AACA;AACA;AACA;AALA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA7HA;AAAA;AAAA;AAgIA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AARA;AASA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAjJA;AAAA;AAAA;AAoJA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AA1KA;AAAA;AAAA;AA6KA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAnMA;AAAA;AAAA;AAuMA;AACA;AAxMA;AAAA;AAAA;AA4MA;AACA;AA7MA;AAAA;AAAA;AAiNA;AACA;AAlNA;AAAA;AAAA;AAsNA;AACA;AAvNA;AAAA;AAAA;AA2NA;AACA;AA5NA;AAAA;AAAA;AAgOA;AACA;AACA;AACA;AACA;AApOA;AAAA;AAAA;AAwOA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAlPA;AAAA;AAAA;AAqPA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA5QA;AAAA;AAAA;AAgRA;AACA;AAjRA;AAAA;AAAA;AAqRA;AACA;AACA;AACA;AACA;AACA;AALA;AAOA;AA5RA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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;;;;;;;AClBA;AACA;AACA;;;;;AACA;AAAA;AACA;AADA;AACA;AAAA;AACA;AACA;AADA;AAFA;AAKA;AACA;;;AACA;AACA;AACA;AADA;AAGA;;;AAEA;AAAA;AACA;AADA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAKA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAGA;;;;AA1BA;AACA;AA4BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/BA;AACA;AACA;AACA;AAEA;;;;;AACA;AAAA;AACA;AADA;AACA;AAAA;AACA;AACA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAFA;AACA;AAIA;AACA;AACA;AAFA;AARA;AAYA;AACA;;;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;;;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;;;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;;;AAEA;AACA;AACA;AADA;AAGA;;;AAEA;AACA;AACA;AACA;AACA;AADA;AAGA;;;AAEA;AACA;AACA;AACA;AACA;AADA;AAGA;;;AAEA;AACA;AACA;AACA;AACA;AADA;AAGA;;;AAEA;AACA;AACA;AACA;AACA;AADA;AAGA;;;AAEA;AACA;AACA;AACA;AACA;AADA;AAGA;;;AAEA;AACA;AACA;AACA;AACA;AADA;AAGA;;;AAEA;AACA;AACA;AACA;AACA;AADA;AAGA;;;AAEA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AALA;AAOA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AANA;AAQA;AAAA;AAKA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AALA;AAOA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AACA;AACA;AACA;AALA;AAOA;AAAA;AAKA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AANA;AAQA;AAAA;AAKA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AANA;AAQA;AAAA;AAKA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AANA;AAQA;AAAA;AAKA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AALA;AAQA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA;;;;AAtNA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;ACNA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AALA;AAOA;AAbA;AAeA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAFA;AAGA;AAAA;AAHA;AAKA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAFA;AAGA;AAAA;AAHA;AAKA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;;;;A","sourceRoot":""}
\ No newline at end of file
diff --git a/build/dev-dist/tola_management_organization-4c0e78fa1302d9fc5d80.js b/build/dev-dist/tola_management_organization-5271c5c80db2208426b1.js
similarity index 91%
rename from build/dev-dist/tola_management_organization-4c0e78fa1302d9fc5d80.js
rename to build/dev-dist/tola_management_organization-5271c5c80db2208426b1.js
index 5b4316ec..53a3f44b 100644
--- a/build/dev-dist/tola_management_organization-4c0e78fa1302d9fc5d80.js
+++ b/build/dev-dist/tola_management_organization-5271c5c80db2208426b1.js
@@ -1111,13 +1111,17 @@ function (_React$Component) {
value: function render() {
var _this2 = this;
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog-entry"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
ref: this.ref,
- className: "expander",
+ className: "changelog-entry__expanding",
style: {
height: !this.state.expanded && (this.props.height || 50)
}
- }, this.props.children), this.state.overflowing && react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("a", {
+ }, this.props.children), this.state.overflowing && react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog-entry__expand-trigger"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("a", {
href: "",
onClick: function onClick(e) {
return _this2.toggleExpanded(e);
@@ -1133,6 +1137,173 @@ function (_React$Component) {
/***/ }),
+/***/ "KnAV":
+/*!************************************!*\
+ !*** ./js/components/changelog.js ***!
+ \************************************/
+/*! exports provided: default */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "q1tI");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
+function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
+
+function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
+
+function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
+
+function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
+
+
+
+var ChangeField = function ChangeField(_ref) {
+ var name = _ref.name,
+ data = _ref.data;
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "change__field"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("strong", null, name), ": ", data != undefined && data != null ? data.toString() : 'N/A');
+};
+
+var ChangeLogEntryHeader = function ChangeLogEntryHeader(_ref2) {
+ var data = _ref2.data;
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", {
+ className: "changelog__entry__header is-expanded"
+ }, " ", react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
+ className: "text-nowrap text-action"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("i", {
+ className: "fas fa-caret-down"
+ }), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("strong", null, data.date)), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
+ className: "text-nowrap"
+ }, data.admin_user), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, data.change_type), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null));
+};
+
+var ChangeLogEntryRow = function ChangeLogEntryRow(_ref3) {
+ var data = _ref3.data;
+
+ if (data.change_type == 'user_programs_updated') {
+ // Create multiple row for program/country changes:
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_0___default.a.Fragment, null, Object.entries(data.diff_list.countries).length > 0 && Object.entries(data.diff_list.countries).map(function (_ref4) {
+ var _ref5 = _slicedToArray(_ref4, 2),
+ id = _ref5[0],
+ country = _ref5[1];
+
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", {
+ key: id,
+ className: "changelog__entry__row"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog__change--prev"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "country",
+ data: country.prev.country
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "role",
+ data: country.prev.role
+ }))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog__change--new"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "country",
+ data: country.new.country
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "role",
+ data: country.new.role
+ }))));
+ }), Object.entries(data.diff_list.programs).length > 0 && Object.entries(data.diff_list.programs).map(function (_ref6) {
+ var _ref7 = _slicedToArray(_ref6, 2),
+ id = _ref7[0],
+ program = _ref7[1];
+
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", {
+ key: id,
+ className: "changelog__entry__row"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog__change--prev"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "program",
+ data: program.prev.program
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "country",
+ data: program.prev.country
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "role",
+ data: program.prev.role
+ }))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog__change--new"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "program",
+ data: program.new.program
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "country",
+ data: program.new.country
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "role",
+ data: program.new.role
+ }))));
+ }));
+ } else {
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", {
+ className: "changelog__entry__row"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
+ className: "text-nowrap"
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog__change--prev"
+ }, data.diff_list.map(function (changeset, id) {
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ key: id,
+ name: changeset.name,
+ data: changeset.prev
+ });
+ }))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog__change--new"
+ }, data.diff_list.map(function (changeset, id) {
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ key: id,
+ name: changeset.name,
+ data: changeset.new
+ });
+ }))));
+ }
+};
+
+var ChangeLogEntry = function ChangeLogEntry(_ref8) {
+ var data = _ref8.data;
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tbody", {
+ className: "changelog__entry",
+ key: data.id
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeLogEntryHeader, {
+ data: data
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeLogEntryRow, {
+ data: data
+ }));
+};
+
+var ChangeLog = function ChangeLog(_ref9) {
+ var data = _ref9.data;
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("table", {
+ className: "table table-sm bg-white table-bordered text-small changelog"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("thead", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap"
+ }, gettext("Date")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap"
+ }, gettext("Admin")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap"
+ }, gettext("Change Type")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap td--half-stretch"
+ }, gettext("Previous Entry")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap td--half-stretch"
+ }, gettext("New Entry")))), data.map(function (entry, id) {
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeLogEntry, {
+ key: id,
+ data: entry
+ });
+ }));
+};
+
+/* harmony default export */ __webpack_exports__["default"] = (ChangeLog);
+
+/***/ }),
+
/***/ "RCjz":
/*!*************************************!*\
!*** ./js/components/pagination.js ***!
@@ -1309,6 +1480,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react_select__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react-select */ "y2Vs");
/* harmony import */ var react_virtualized__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react-virtualized */ "c7k8");
/* harmony import */ var components_expander__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! components/expander */ "H4hL");
+/* harmony import */ var components_changelog__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! components/changelog */ "KnAV");
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
@@ -1336,6 +1508,7 @@ function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || func
+
var status_options = [{
value: true,
label: gettext('Active')
@@ -1344,13 +1517,6 @@ var status_options = [{
label: gettext('Inactive')
}];
-var ChangesetEntry = function ChangesetEntry(_ref) {
- var name = _ref.name,
- type = _ref.type,
- data = _ref.data;
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("strong", null, name), ": ", data != undefined && data != null ? data.toString() : 'N/A');
-};
-
var EditOrganizationHistory =
/*#__PURE__*/
function (_React$Component) {
@@ -1433,31 +1599,9 @@ function (_React$Component) {
onClick: function onClick() {
return _this2.onReset();
}
- }, gettext("Reset"))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("table", {
- className: "table table-sm text-small"
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("thead", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("Date")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("Admin User")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("Change Type")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("Previous Entry")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("New Entry")))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tbody", null, this.props.organizationHistoryData.map(function (entry) {
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", {
- key: entry.id
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, entry.date), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, entry.admin_user), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, entry.change_type), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
- className: "expand-section"
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(components_expander__WEBPACK_IMPORTED_MODULE_4__["default"], null, entry.diff_list.map(function (changeset) {
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangesetEntry, {
- key: changeset.name,
- name: changeset.name,
- type: entry.change_type,
- data: changeset.prev
- });
- }))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
- className: "expand-section"
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(components_expander__WEBPACK_IMPORTED_MODULE_4__["default"], null, entry.diff_list.map(function (changeset) {
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangesetEntry, {
- key: changeset.name,
- name: changeset.name,
- type: entry.change_type,
- data: changeset.new
- });
- }))));
- }))));
+ }, gettext("Reset"))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(components_changelog__WEBPACK_IMPORTED_MODULE_5__["default"], {
+ data: this.props.organizationHistoryData
+ }));
}
}]);
@@ -2246,4 +2390,4 @@ var fetchOrganizationHistory = function fetchOrganizationHistory(id) {
/***/ })
},[["j6MH","runtime","vendors"]]]);
-//# sourceMappingURL=tola_management_organization-4c0e78fa1302d9fc5d80.js.map
\ No newline at end of file
+//# sourceMappingURL=tola_management_organization-5271c5c80db2208426b1.js.map
\ No newline at end of file
diff --git a/build/dev-dist/tola_management_organization-5271c5c80db2208426b1.js.map b/build/dev-dist/tola_management_organization-5271c5c80db2208426b1.js.map
new file mode 100644
index 00000000..8efd01a3
--- /dev/null
+++ b/build/dev-dist/tola_management_organization-5271c5c80db2208426b1.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"tola_management_organization-5271c5c80db2208426b1.js","sources":["webpack:///./js/pages/tola_management_pages/organization/models.js","webpack:///./js/components/virtualized-react-select.js","webpack:///./js/components/loading-spinner.js","webpack:///./js/pages/tola_management_pages/organization/views.js","webpack:///./js/components/expander.js","webpack:///./js/components/changelog.js","webpack:///./js/components/pagination.js","webpack:///./js/pages/tola_management_pages/organization/components/organization_editor.js","webpack:///./js/pages/tola_management_pages/organization/components/edit_organization_history.js","webpack:///./js/components/management-table.js","webpack:///./js/api.js","webpack:///./js/components/checkboxed-multi-select.js","webpack:///./js/pages/tola_management_pages/organization/index.js","webpack:///./js/components/folding-sidebar.js","webpack:///./js/pages/tola_management_pages/organization/components/edit_organization_profile.js","webpack:///./js/pages/tola_management_pages/organization/api.js"],"sourcesContent":["import { observable, computed, action, runInAction } from \"mobx\";\nimport api from './api';\n\nconst default_organization = {\n id: null ,\n is_active: false,\n mode_of_contact: \"\",\n name: \"\",\n organization_url: null,\n primary_address: \"\",\n primary_contact_email: \"\",\n primary_contact_name: \"\",\n primary_contact_phone: \"\",\n sectors: [],\n}\n\nexport class OrganizationStore {\n @observable organizations = {}\n @observable organizations_listing = []\n @observable organizations_count = 0\n @observable total_pagees = 0\n @observable fetching = false\n @observable fetching_editing_target = false\n @observable current_page = 0\n @observable saving = false\n\n @observable bulk_targets = new Map()\n @observable bulk_targets_all = false\n\n available_programs = {}\n available_organizations = {}\n available_sectors = {}\n available_countries = {}\n program_selections = []\n organization_selections = []\n sector_selections = []\n country_selections = []\n\n @observable editing_target = null\n @observable editing_target_data = {...default_organization}\n @observable editing_target_history = []\n @observable editing_errors = {}\n\n @observable filters = {\n countries: [],\n organizations: [],\n programs: [],\n sectors: [],\n organization_status: '',\n }\n\n organization_status_options = [\n {value: 1, label: gettext('Active')},\n {value: 0, label: gettext('Inactive')}\n ]\n\n constructor(programs, organizations, sectors, countries, country_filter, program_filter) {\n this.available_programs = programs\n this.available_organizations = organizations\n this.available_sectors = sectors\n this.available_countries = countries\n this.organization_selections = Object.entries(organizations).map(([id, org]) => ({value: org.id, label: org.name}))\n this.program_selections = Object.entries(programs).map(([id, program]) => ({value: program.id, label: program.name}))\n this.sector_selections = Object.entries(sectors).map(([id, sector]) => ({value: sector.id, label: sector.name}))\n this.country_selections = Object.entries(countries).map(([id, country]) => ({value: country.id, label: country.name}))\n this.filters.countries = country_filter.map(id => this.available_countries[id]).map(country => ({label: country.name, value: country.id}))\n this.filters.programs = program_filter.filter(id => programs[id]).map(id => ({label: programs[id].name, value: id}))\n this.fetchOrganizations()\n }\n\n marshalFilters(filters) {\n return Object.entries(filters).reduce((xs, x) => {\n if(Array.isArray(x[1])) {\n xs[x[0]] = x[1].map(x => x.value)\n } else {\n xs[x[0]] = x[1].value\n }\n return xs\n }, {})\n }\n\n updateLocalOrganization(id, applied_data, aggregates) {\n this.organizations[id] = {\n id: id,\n name: applied_data.name,\n program_count: aggregates.program_count,\n user_count: aggregates.user_count,\n is_active: applied_data.is_active\n }\n }\n\n onSaveErrorHandler() {\n PNotify.error({text: gettext('Saving Failed'), delay: 5000});\n }\n\n onSaveSuccessHandler() {\n PNotify.success({text: gettext('Successfully Saved'), delay: 5000})\n }\n\n @action\n fetchOrganizations() {\n this.fetching = true\n\n api.fetchOrganizationsWithFilter(this.current_page + 1, this.marshalFilters(this.filters)).then(results => {\n runInAction(() => {\n this.fetching = false\n this.organizations = results.organizations.reduce((xs, x) => {\n xs[x.id] = x\n return xs\n }, {})\n this.organizations_listing = results.organizations.map(o => o.id)\n this.organizations_count = results.total_organizations\n this.total_pages = results.total_pages\n this.bulk_targets = new Map(Object.entries(this.organizations).map(([_, organization]) => [organization.id, false]))\n })\n })\n }\n\n @action\n applyFilters() {\n this.current_page = 0\n this.fetchOrganizations()\n }\n\n @action\n createOrganization() {\n const new_organization = {\n id: \"new\",\n name: \"\",\n program_count: 0,\n user_count: 0,\n is_active: false\n }\n if(this.editing_target !== \"new\") {\n this.organizations_listing.unshift(\"new\")\n }\n\n this.editing_errors = {}\n this.organizations[\"new\"] = new_organization\n this.editing_target = new_organization.id\n this.editing_target_data = {...default_organization}\n }\n\n @action\n updateOrganizationProfile(id, new_data) {\n this.saving = true\n api.updateOrganization(id, new_data).then(updated_data => api.fetchOrganizationAggregates(id).then(aggregates => {\n runInAction(() => {\n this.saving = false\n this.updateLocalOrganization(id, updated_data, aggregates)\n this.editing_target = null\n this.editing_target_data = {...default_organization}\n })\n this.onSaveSuccessHandler()\n })).catch((error) => {\n runInAction(() => {\n this.saving = false\n this.editing_errors = error.response.data\n })\n this.onSaveErrorHandler()\n })\n }\n\n @action\n saveNewOrganization(new_data) {\n this.saving = true\n new_data.is_active = true;\n api.createOrganization(new_data).then(result => {\n runInAction(() => {\n this.saving = false\n this.updateLocalOrganization(result.id, result, {program_count: 0, user_count: 0})\n this.organizations_listing.shift()\n delete this.organizations[\"new\"]\n this.organizations_listing.unshift(result.id)\n this.editing_target = null\n this.editing_target_data = {...default_organization}\n this.bulk_targets = new Map(Object.entries(this.organizations).map(([_, organization]) => [organization.id, false]))\n })\n this.onSaveSuccessHandler()\n }).catch(error => {\n runInAction(() => {\n this.saving = false\n this.editing_errors = error.response.data\n })\n this.onSaveErrorHandler()\n })\n }\n\n @action\n saveNewOrganizationAndAddAnother(new_data) {\n this.saving = true\n new_data.is_active = true;\n api.createOrganization(new_data).then(result => {\n runInAction(() => {\n this.saving = false\n this.updateLocalOrganization(result.id, result, {program_count: 0, user_count: 0})\n this.organizations_listing.shift()\n delete this.organizations[\"new\"]\n this.organizations_listing.unshift(result.id)\n this.editing_target = null\n this.editing_target_data = {...default_organization}\n this.bulk_targets = new Map(Object.entries(this.organizations).map(([_, organization]) => [organization.id, false]))\n })\n this.onSaveSuccessHandler()\n }).catch(error => {\n runInAction(() => {\n this.saving = false\n this.editing_errors = error.response.data\n })\n this.onSaveErrorHandler()\n })\n }\n\n @action\n changeSectorFilter(sectors) {\n this.filters.sectors = sectors\n }\n\n @action\n changeCountryFilter(countries) {\n this.filters.countries = countries\n }\n\n @action\n changeProgramFilter(programs) {\n this.filters.programs = programs\n }\n\n @action\n changeOrganizationFilter(organizations) {\n this.filters.organizations = organizations\n }\n\n @action\n changeOrganizationStatusFilter(status) {\n this.filters.organization_status = status\n }\n\n @action\n changePage(page) {\n if(this.current_page != page.selected) {\n this.current_page = page.selected\n this.fetchOrganizations()\n }\n }\n\n @action\n toggleBulkTargetsAll() {\n this.bulk_targets_all = !this.bulk_targets_all;\n if(this.bulk_targets_all) {\n this.bulk_targets.forEach((val, key, map) => {\n map.set(key, true)\n })\n } else {\n this.bulk_targets.forEach((val, key, map) => {\n map.set(key, false)\n })\n }\n }\n\n @action\n toggleEditingTarget(organization_id) {\n this.editing_target_data = {...default_organization}\n this.editing_errors = {}\n\n if(this.editing_target == \"new\") {\n this.organizations_listing.shift()\n }\n\n if(this.editing_target == organization_id) {\n this.editing_target = false\n } else {\n this.editing_target = organization_id\n this.fetching_editing_target = true\n if(!(this.editing_target == 'new')) {\n Promise.all([api.fetchOrganization(organization_id), api.fetchOrganizationHistory(organization_id)]).then(([organization, history]) => {\n runInAction(() => {\n this.fetching_editing_target = false\n this.editing_target_data = organization\n this.editing_target_history = history\n })\n })\n }\n }\n }\n\n @action\n toggleBulkTarget(target_id) {\n this.bulk_targets.set(target_id, !this.bulk_targets.get(target_id))\n }\n\n @action\n clearFilters() {\n this.filters = {\n countries: [],\n organizations: [],\n programs: [],\n sectors: [],\n organization_status: '',\n }\n }\n}\n","import React from 'react'\nimport {List, AutoSizer, CellMeasurer, CellMeasurerCache} from 'react-virtualized'\nimport Select, {components} from 'react-select'\n\nexport class VirtualizedMenuList extends React.PureComponent {\n constructor(props) {\n super(props)\n this.cache = new CellMeasurerCache({\n fixedWidth: true,\n defaultHeight: 35,\n })\n this.filter_val = \"\"\n }\n\n render() {\n const {options, children, maxHeight, getValue, selectProps} = this.props\n const rowCount = children.length || 0\n\n //gotta be a way to improve this. it's ok after the first couple of\n //characters search, but it's slow prior to that\n if(selectProps.inputValue !== this.filter_val) {\n this.filter_val = selectProps.inputValue\n this.cache.clearAll()\n }\n\n return (\n \n
\n
\n {({width, height}) => {\n return No selections available
}\n rowRenderer={\n ({index, parent, key, style}) =>\n \n {children[index]}
\n \n }/>\n }}\n
\n
\n
\n )\n }\n}\n\nconst VirtualizedSelect = props => (\n \n)\n\nexport default VirtualizedSelect\n","\nimport React from 'react'\n\nconst LoadingSpinner = ({children, isLoading, className, ...props}) => {\n const loading = (isLoading)?'loading':''\n return \n}\n\nexport default LoadingSpinner\n","import React from 'react';\nimport { observer } from \"mobx-react\"\nimport Select from 'react-select'\nimport ManagementTable from 'components/management-table'\nimport Pagination from 'components/pagination'\nimport CheckboxedMultiSelect from 'components/checkboxed-multi-select'\n\nimport OrganizationEditor from './components/organization_editor'\nimport EditOrganizationProfile from './components/edit_organization_profile'\nimport EditOrganizationHistory from './components/edit_organization_history'\n\nimport LoadingSpinner from 'components/loading-spinner'\nimport FoldingSidebar from 'components/folding-sidebar'\n\nconst CountryFilter = observer(({store, selections}) => {\n return \n {gettext(\"Countries\")} \n store.changeCountryFilter(e)}\n placeholder={gettext(\"None Selected\")}\n id=\"countries_permitted_filter\" />\n
\n})\n\nconst ProgramFilter = observer(({store, selections}) => {\n return \n {gettext(\"Programs\")} \n store.changeProgramFilter(e)}\n placeholder={gettext(\"None Selected\")}\n id=\"programs_filter\" />\n
\n})\n\nconst OrganizationFilter = observer(({store, selections}) => {\n return \n {gettext(\"Organizations\")} \n store.changeOrganizationFilter(e)}\n placeholder={gettext(\"None Selected\")}\n id=\"organization_filter\" />\n
\n})\n\nconst SectorFilter = observer(({store, selections}) => {\n return \n {gettext(\"Sectors\")} \n store.changeSectorFilter(e)}\n placeholder={gettext(\"None Selected\")}\n id=\"sector_filter\" />\n
\n})\n\nexport const IndexView = observer(\n ({store}) => {\n return \n
\n \n
\n
\n
\n
\n
\n {gettext(\"Status\")} \n store.changeOrganizationStatusFilter(e)}\n placeholder={gettext(\"None Selected\")}\n id=\"status_filter\" />\n
\n
\n store.applyFilters()}>{gettext(\"Apply\")} \n store.clearFilters()}>{gettext(\"Reset\")} \n
\n
\n \n
\n
\n
\n \n
store.organizations[id])}\n keyField=\"id\"\n HeaderRow={({Col, Row}) =>\n \n \n \n {gettext(\"Organization\")}\n {gettext(\"Programs\")}\n {gettext(\"Users\")}\n {gettext(\"Status\")}\n
\n }\n Row={({Col, Row, data}) =>\n \n \n \n \n store.updateOrganizationProfile(data.id, new_organization_data)}\n onSaveNew={(new_organization_data) => store.saveNewOrganization(new_organization_data)}\n onSaveNewAndAddAnother={(new_organization_data) => store.saveNewOrganizationAndAddAnother(new_organization_data)} />\n \n )}\n HistorySection={observer(() =>\n \n store.updateOrganizationProfile(data.id, new_organization_data)}/>\n \n )}\n />\n \n }>\n \n \n \n store.toggleEditingTarget(data.id)} >\n \n {data.name || \"---\"}\n
\n \n \n \n \n {data.program_count} {gettext(\"programs\")}\n \n \n \n \n \n {data.user_count} {gettext(\"users\")}\n \n \n {data.is_active?'Active':'Inactive'}\n
\n }\n />\n \n \n
\n
{store.organizations_count?`${store.organizations_count} ${gettext(\"organizations\")}`:`--`}
\n
\n {store.total_pages &&\n
store.changePage(page)} />\n }\n \n
\n
\n
\n }\n)\n","import React from 'react'\n\nclass Expander extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n expanded: false,\n overflowing: false,\n }\n this.ref = React.createRef()\n }\n\n componentDidMount() {\n if(this.ref.current.scrollHeight > this.ref.current.clientHeight) {\n this.setState({overflowing: true})\n }\n }\n\n toggleExpanded(e) {\n e.preventDefault()\n this.setState({\n expanded: !this.state.expanded\n })\n }\n\n render() {\n return \n
\n {this.props.children}\n
\n {this.state.overflowing &&\n
\n }\n
\n }\n}\n\nexport default Expander\n","import React from 'react'\n\nconst ChangeField = ({name, data}) => {\n return \n {name} : {(data != undefined && data != null)?data.toString():'N/A'}\n
\n}\n\nconst ChangeLogEntryHeader = ({data}) => {\n return {/* TODO: apply is-expanded dynamically */}\n {data.date} \n {data.admin_user} \n {data.change_type} \n \n \n \n}\n\nconst ChangeLogEntryRow = ({data}) => {\n if (data.change_type == 'user_programs_updated') {\n // Create multiple row for program/country changes:\n return \n {Object.entries(data.diff_list.countries).length > 0 &&\n Object.entries(data.diff_list.countries).map(([id, country]) =>\n \n \n \n \n \n \n \n \n
\n \n \n \n \n \n
\n \n \n )\n }\n {Object.entries(data.diff_list.programs).length > 0 &&\n Object.entries(data.diff_list.programs).map(([id, program]) =>\n \n \n \n \n \n \n \n \n \n
\n \n \n \n \n \n \n
\n \n \n )\n }\n \n } else {\n return \n \n \n \n \n \n {data.diff_list.map((changeset, id) =>\n \n )}\n
\n \n \n \n {data.diff_list.map((changeset, id) =>\n \n )}\n
\n \n \n }\n}\n\nconst ChangeLogEntry = ({data}) => {\n return \n \n \n \n}\n\nconst ChangeLog = ({data}) => {\n return \n \n \n {gettext(\"Date\")} \n {gettext(\"Admin\")} \n {gettext(\"Change Type\")} \n {gettext(\"Previous Entry\")} \n {gettext(\"New Entry\")} \n \n \n {data.map((entry, id) =>\n \n )}\n
\n}\n\nexport default ChangeLog\n","import React from 'react'\nimport ReactPaginate from 'react-paginate'\nimport { observer } from \"mobx-react\"\n\n/***\n Props:\n\n - pageCount: total number of pages\n - initialPage: which page should be highlighted as active initially\n - onPageChange: a function to receive the newly selected page\n*/\nconst Pagination = (props) => {\n return \n}\n\nexport default Pagination\n","import React from 'react'\nimport { observer } from \"mobx-react\"\n\n@observer\nexport default class OrganizationEditor extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n active_page: 'profile'\n }\n }\n\n updateActivePage(new_page) {\n if(!this.props.new) {\n this.setState({active_page: new_page})\n }\n }\n\n render() {\n const {ProfileSection, HistorySection} = this.props\n\n const profile_active_class = (this.state.active_page == 'profile')?'active':''\n const history_active_class = (this.state.active_page == 'status_and_history')?'active':''\n const new_class = (this.props.new)?'disabled':''\n\n return (\n \n
\n
\n {this.state.active_page == 'profile' &&\n
\n }\n\n {this.state.active_page == 'status_and_history' &&\n
\n }\n
\n
\n )\n }\n}\n","import React from 'react'\nimport { observer } from \"mobx-react\"\nimport Select from 'react-select'\nimport {AutoSizer, Table, Column, CellMeasurer, CellMeasurerCache} from 'react-virtualized'\nimport Expander from 'components/expander'\nimport ChangeLog from 'components/changelog'\n\nconst status_options = [\n {value: true, label: gettext('Active')},\n {value: false, label: gettext('Inactive')}\n]\n\nexport default class EditOrganizationHistory extends React.Component {\n\n constructor(props) {\n super(props)\n const data = {\n ...props.organizationData,\n is_active: status_options.find(op => op.value == props.organizationData.is_active)\n }\n this.state = {\n initial_data: data,\n data: {...data}\n }\n }\n\n onChange(new_value) {\n this.state.data.is_active = new_value\n\n this.setState({\n data: this.state.data\n })\n }\n\n onReset() {\n this.setState({\n data: this.state.initial_data\n })\n }\n\n save(e) {\n e.preventDefault()\n this.props.onSave({\n ...this.state.data,\n is_active: this.state.data.is_active.value,\n sectors: this.state.data.sectors.map(sector => sector.id)\n })\n }\n\n render() {\n return \n
{this.state.data.name ? this.state.data.name+\": \": \"\"}{gettext(\"Status and history\")} \n
\n this.onChange(new_value)} />\n
\n
\n this.save(e)}>{gettext(\"Save Changes\")} \n this.onReset()}>{gettext(\"Reset\")} \n
\n\n
\n\n
\n }\n}\n","import { observer } from \"mobx-react\"\nimport React from 'react';\nimport classNames from 'classnames';\n\n// TODO: \"size\" is no longer used\nconst ColumnComponent = ({className, size, ...props}) => {props.children} \n\n// TODO: this is redundant with ColumnComponent\nconst HeaderColumnComponent = ({className, size, ...props}) => {props.children} \n\nconst InnerRowComponent = ({className, ...props}) => {props.children} \n\n// TODO: this is redundant with InnerRowComponent\nconst HeaderRowComponent = ({className, ...props}) => {props.children} \n\n/***\n A wrapper for the rendering of the given row renderer, it takes and expando\n renderer used to render expanded content\n\n Props:\n - expanded: whether the expando content is shown or not\n - Expando: The content to render when the expando is shown\n*/\nconst RowComponent = observer(({className, expanded, Expando, ...props}) => {\n if(Expando) {\n const ObservedExpando = observer(Expando)\n return \n {props.children} \n {expanded && }\n \n } else {\n return \n {props.children} \n \n }\n})\nconst ExpandoWrapper = ({className, ...props}) => {props.children} \n\nconst RowList = observer(({data, Row, keyField, ...props}) => {\n const ObservedRow = observer(Row)\n return data.map(row_data => )\n})\n\n/*\n Props:\n\n - HeaderRow: a function to render the header row. it receives a component\n prop to render the header column and row\n\n - Row: a function used to render each row. it receives a component prop to\n render the row (see RowComponent), it receives the relevant data for that\n row as a prop: data\n\n - data: the dataset used to render the table, it must be an array\n\n - keyField: field to use for key on rows and expando checking\n\n */\nconst ManagementTable = observer(({HeaderRow, className, ...props}) => {\n const ObservedHeaderRow = observer(HeaderRow)\n return \n})\nexport default ManagementTable\n","import axios from 'axios';\n\nexport const api = axios.create({\n withCredentials: true,\n baseURL: '/api/',\n headers: {\n \"X-CSRFToken\": document.cookie.replace(/(?:(?:^|.*;\\s*)csrftoken\\s*\\=\\s*([^;]*).*$)|^.*$/, \"$1\")\n }\n});\n","import React from 'react'\nimport Select, {components} from 'react-select'\nimport {VirtualizedMenuList as MenuList} from './virtualized-react-select'\nimport {observer} from 'mobx-react'\n\nconst Option = props => {\n return (components.Option &&\n \n {\n //we can let the outer component manage state\n }}\n />\n \n {props.data.label}\n \n )\n}\n\nconst CheckboxedMultiSelect = observer(props => (\n \n))\n\nexport default CheckboxedMultiSelect\n","import React from 'react';\nimport ReactDOM from 'react-dom';\nimport {OrganizationStore} from './models';\nimport {IndexView} from './views';\n\n/*\n * Model/Store setup\n */\nconst store = new OrganizationStore(\n jsContext.programs,\n jsContext.organizations,\n jsContext.sectors,\n jsContext.countries,\n jsContext.country_filter,\n jsContext.program_filter,\n)\n\nReactDOM.render(\n ,\n document.querySelector('#app_root')\n)\n","import React from 'react'\n\nclass Expander extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n folded: false,\n }\n }\n\n toggleFolded() {\n this.setState({\n folded: !this.state.folded\n })\n }\n\n render() {\n const {className, ...props} = this.props\n const icon = (this.state.folded)?\"fa-chevron-right\":\"fa-chevron-left\"\n return \n {!this.state.folded &&\n
{this.props.children} \n }\n\n
this.toggleFolded()}>\n \n
\n
\n }\n}\n\nexport default Expander\n","import React from 'react'\nimport CheckboxedMultiSelect from 'components/checkboxed-multi-select'\nimport { observer } from \"mobx-react\"\n\n@observer\nexport default class EditOrganizationProfile extends React.Component {\n constructor(props) {\n super(props)\n const o = props.organizationData\n const data = {\n ...o,\n sectors: o.sectors.map(sector => ({value: sector.id, label: sector.sector}))\n }\n\n this.state = {\n initial_data: data,\n managed_data: {...data}\n }\n }\n\n save(e) {\n e.preventDefault()\n this.props.onSave({...this.state.managed_data, sectors: this.state.managed_data.sectors.map(sector => sector.value)})\n }\n\n saveNew(e) {\n e.preventDefault()\n this.props.onSaveNew({...this.state.managed_data, sectors: this.state.managed_data.sectors.map(sector => sector.value)})\n }\n\n saveNewAndAddAnother(e) {\n e.preventDefault()\n this.props.onSaveNewAndAddAnother({...this.state.managed_data, sectors: this.state.managed_data.sectors.map(sector => sector.value)})\n }\n\n resetForm() {\n this.setState({\n managed_data: this.state.initial_data\n })\n }\n\n updateName(new_name) {\n let new_data = this.state.managed_data\n new_data.name = new_name\n this.setState({\n managed_data: new_data\n })\n }\n\n updateSectors(new_sectors) {\n let new_data = this.state.managed_data\n new_data.sectors = new_sectors\n this.setState({\n managed_data: new_data\n })\n }\n\n updatePrimaryAddress(new_address) {\n let new_data = this.state.managed_data\n new_data.primary_address = new_address\n this.setState({\n managed_data: new_data\n })\n }\n\n updatePrimaryContactName(new_name) {\n let new_data = this.state.managed_data\n new_data.primary_contact_name = new_name\n this.setState({\n managed_data: new_data\n })\n }\n\n updatePrimaryContactEmail(new_email) {\n let new_data = this.state.managed_data\n new_data.primary_contact_email = new_email\n this.setState({\n managed_data: new_data\n })\n }\n\n updatePrimaryContactPhone(new_phone) {\n let new_data = this.state.managed_data\n new_data.primary_contact_phone = new_phone\n this.setState({\n managed_data: new_data\n })\n }\n\n updateModeOfContact(new_mode_of_contact) {\n let new_data = this.state.managed_data\n new_data.mode_of_contact = new_mode_of_contact\n this.setState({\n managed_data: new_data\n })\n }\n\n render() {\n let od = this.state.managed_data\n let errors = this.props.errors\n let error_classes = {\n name: (errors.name)?'is-invalid':'',\n primary_address: (errors.primary_address)?'is-invalid':'',\n primary_contact_name: (errors.primary_contact_name)?'is-invalid':'',\n primary_contact_email: (errors.primary_contact_email)?'is-invalid':'',\n primary_contact_phone: (errors.primary_contact_phone)?'is-invalid':'',\n }\n return (\n \n
{od.name ? od.name+\": \": \"\"}{gettext(\"Profile\")} \n
\n \n
{gettext(\"Organization name\")}* \n
this.updateName(e.target.value) }\n className={\"form-control \"+error_classes.name}\n id=\"organization-name-input\"\n required />\n {errors.name &&\n
\n {errors.name}\n
\n }\n
\n \n Sectors \n this.updateSectors(e)}\n placeholder={gettext(\"None Selected\")}\n id=\"sectors-input\" />\n
\n \n
{gettext(\"Primary Address\")}* \n
this.updatePrimaryAddress(e.target.value)}\n className={\"form-control \"+error_classes.primary_address}\n id=\"primary-address-input\"\n required />\n {errors.primary_address &&\n \n {errors.primary_address}\n
\n }\n \n \n
{gettext(\"Primary Contact Name\")}* \n
this.updatePrimaryContactName(e.target.value) }\n className={\"form-control \"+error_classes.primary_contact_name}\n id=\"primary-contact-name-input\"\n required />\n {errors.primary_contact_name &&\n
\n {errors.primary_contact_name}\n
\n }\n
\n \n
{gettext(\"Primary Contact Email\")}* \n
this.updatePrimaryContactEmail(e.target.value) }\n className={\"form-control \"+error_classes.primary_contact_email}\n id=\"primary-contact-email-input\"\n required />\n {errors.primary_contact_email &&\n
\n {errors.primary_contact_email}\n
\n }\n
\n \n
{gettext(\"Primary Contact Phone Number\")}* \n
this.updatePrimaryContactPhone(e.target.value) }\n className={\"form-control \"+error_classes.primary_contact_phone}\n id=\"primary-contact-phone-input\"\n required />\n {errors.primary_contact_phone &&\n
\n {errors.primary_contact_phone}\n
\n }\n
\n \n {gettext(\"Preferred Mode of Contact\")} \n this.updateModeOfContact(e.target.value) }\n className=\"form-control\"\n id=\"mode-of-contact-input\" />\n
\n {this.props.new &&\n \n this.saveNew(e)}>{gettext(\"Save Changes\")} \n this.saveNewAndAddAnother(e)}>{gettext(\"Save and Add Another\")} \n this.resetForm()}>{gettext(\"Reset\")} \n
\n }\n {!this.props.new &&\n \n this.save(e)}>{gettext(\"Save Changes\")} \n this.resetForm()}>{gettext(\"Reset\")} \n
\n }\n \n
\n )\n }\n}\n","import {api} from '../../../api';\n\nexport const fetchOrganizationsWithFilter = (page, filters) => api.get('/tola_management/organization/', {params: {page: page, ...filters}}).then(response => {\n let data = response.data\n let total_results_count = data.count\n let current_results_count = data.results.length\n let total_pages = data.page_count\n\n return {\n organizations: data.results,\n total_pages: total_pages,\n total_organizations: total_results_count,\n next_page: data.next,\n prev_page: data.previous\n }\n})\n\nexport const fetchOrganization = (id) => api.get(`/tola_management/organization/${id}/`).then(response => response.data)\n\nexport const updateOrganization = (id, new_data) => api.put(`/tola_management/organization/${id}/`, {\n ...new_data,\n sectors: new_data.sectors.map(sector => ({id: sector}))\n}).then(response => response.data)\n\nexport const createOrganization = (new_data) => api.post(`/tola_management/organization/`, {\n ...new_data,\n sectors: new_data.sectors.map(sector => ({id: sector}))\n}).then(response => response.data)\n\nexport const fetchOrganizationAggregates = id => api.get(`/tola_management/organization/${id}/aggregate_data/`).then(response => response.data)\n\nexport const fetchOrganizationHistory = id => api.get(`/tola_management/organization/${id}/history/`).then(response => response.data)\n\nexport default {\n fetchOrganizationsWithFilter,\n fetchOrganization,\n fetchOrganizationHistory,\n fetchOrganizationAggregates,\n updateOrganization,\n createOrganization,\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAVA;AAaA;AAAA;AAAA;AAwCA;AAAA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AAJA;AAAA;AAAA;AACA;AAAA;AAAA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AArDA;AAAA;AAAA;AAuDA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AA/DA;AAAA;AAAA;AAkEA;AACA;AACA;AACA;AACA;AACA;AALA;AAOA;AAzEA;AAAA;AAAA;AA4EA;AAAA;AAAA;AAAA;AACA;AA7EA;AAAA;AAAA;AAgFA;AAAA;AAAA;AAAA;AACA;AAjFA;AAAA;AAAA;AAoFA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AACA;AACA;AACA;AApGA;AAAA;AAAA;AAwGA;AACA;AACA;AA1GA;AAAA;AAAA;AA8GA;AACA;AACA;AACA;AACA;AACA;AALA;AACA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA7HA;AAAA;AAAA;AAgIA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AARA;AASA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAjJA;AAAA;AAAA;AAoJA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AA1KA;AAAA;AAAA;AA6KA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAnMA;AAAA;AAAA;AAuMA;AACA;AAxMA;AAAA;AAAA;AA4MA;AACA;AA7MA;AAAA;AAAA;AAiNA;AACA;AAlNA;AAAA;AAAA;AAsNA;AACA;AAvNA;AAAA;AAAA;AA2NA;AACA;AA5NA;AAAA;AAAA;AAgOA;AACA;AACA;AACA;AACA;AApOA;AAAA;AAAA;AAwOA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAlPA;AAAA;AAAA;AAqPA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AA5QA;AAAA;AAAA;AAgRA;AACA;AAjRA;AAAA;AAAA;AAqRA;AACA;AACA;AACA;AACA;AACA;AALA;AAOA;AA5RA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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","sourceRoot":""}
\ No newline at end of file
diff --git a/build/dev-dist/tola_management_program-feca61b7873f2fd0e205.js b/build/dev-dist/tola_management_program-1c0ce8637a72447286c3.js
similarity index 92%
rename from build/dev-dist/tola_management_program-feca61b7873f2fd0e205.js
rename to build/dev-dist/tola_management_program-1c0ce8637a72447286c3.js
index 681f0998..a7a4d76e 100644
--- a/build/dev-dist/tola_management_program-feca61b7873f2fd0e205.js
+++ b/build/dev-dist/tola_management_program-1c0ce8637a72447286c3.js
@@ -239,6 +239,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var react_virtualized__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react-virtualized */ "c7k8");
/* harmony import */ var mobx_react__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! mobx-react */ "okNM");
/* harmony import */ var components_expander__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! components/expander */ "H4hL");
+/* harmony import */ var components_changelog__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! components/changelog */ "KnAV");
var _class;
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
@@ -264,6 +265,7 @@ function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || func
+
var status_options = [{
value: 'Funded',
label: 'Funded'
@@ -271,14 +273,6 @@ var status_options = [{
value: 'Completed',
label: 'Completed'
}];
-
-var ChangesetEntry = function ChangesetEntry(_ref) {
- var name = _ref.name,
- type = _ref.type,
- data = _ref.data;
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("strong", null, name), ": ", data != undefined && data != null ? data.toString() : 'N/A');
-};
-
var ProgramHistory = Object(mobx_react__WEBPACK_IMPORTED_MODULE_3__["observer"])(_class =
/*#__PURE__*/
function (_React$Component) {
@@ -363,33 +357,9 @@ function (_React$Component) {
onClick: function onClick() {
return _this2.onReset();
}
- }, gettext("Reset"))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("table", {
- className: "table table-sm text-small"
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("thead", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("Date")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("Admin User")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("Change Type")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("Previous Entry")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("New Entry")))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tbody", null, this.props.history.map(function (entry) {
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", {
- key: entry.id
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
- className: "text-nowrap"
- }, entry.date), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, entry.admin_user), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, entry.change_type), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
- className: "expand-section"
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(components_expander__WEBPACK_IMPORTED_MODULE_4__["default"], null, entry.diff_list.map(function (changeset) {
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangesetEntry, {
- key: changeset.name,
- name: changeset.name,
- type: entry.change_type,
- data: changeset.prev
- });
- }))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
- className: "expand-section"
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(components_expander__WEBPACK_IMPORTED_MODULE_4__["default"], null, entry.diff_list.map(function (changeset) {
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangesetEntry, {
- key: changeset.name,
- name: changeset.name,
- type: entry.change_type,
- data: changeset.new
- });
- }))));
- }))));
+ }, gettext("Reset"))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(components_changelog__WEBPACK_IMPORTED_MODULE_5__["default"], {
+ data: this.props.history
+ }));
}
}]);
@@ -583,13 +553,17 @@ function (_React$Component) {
value: function render() {
var _this2 = this;
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog-entry"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
ref: this.ref,
- className: "expander",
+ className: "changelog-entry__expanding",
style: {
height: !this.state.expanded && (this.props.height || 50)
}
- }, this.props.children), this.state.overflowing && react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("a", {
+ }, this.props.children), this.state.overflowing && react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog-entry__expand-trigger"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("a", {
href: "",
onClick: function onClick(e) {
return _this2.toggleExpanded(e);
@@ -605,6 +579,173 @@ function (_React$Component) {
/***/ }),
+/***/ "KnAV":
+/*!************************************!*\
+ !*** ./js/components/changelog.js ***!
+ \************************************/
+/*! exports provided: default */
+/***/ (function(module, __webpack_exports__, __webpack_require__) {
+
+"use strict";
+__webpack_require__.r(__webpack_exports__);
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "q1tI");
+/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
+function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
+
+function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
+
+function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
+
+function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
+
+
+
+var ChangeField = function ChangeField(_ref) {
+ var name = _ref.name,
+ data = _ref.data;
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "change__field"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("strong", null, name), ": ", data != undefined && data != null ? data.toString() : 'N/A');
+};
+
+var ChangeLogEntryHeader = function ChangeLogEntryHeader(_ref2) {
+ var data = _ref2.data;
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", {
+ className: "changelog__entry__header is-expanded"
+ }, " ", react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
+ className: "text-nowrap text-action"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("i", {
+ className: "fas fa-caret-down"
+ }), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("strong", null, data.date)), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
+ className: "text-nowrap"
+ }, data.admin_user), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, data.change_type), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null));
+};
+
+var ChangeLogEntryRow = function ChangeLogEntryRow(_ref3) {
+ var data = _ref3.data;
+
+ if (data.change_type == 'user_programs_updated') {
+ // Create multiple row for program/country changes:
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_0___default.a.Fragment, null, Object.entries(data.diff_list.countries).length > 0 && Object.entries(data.diff_list.countries).map(function (_ref4) {
+ var _ref5 = _slicedToArray(_ref4, 2),
+ id = _ref5[0],
+ country = _ref5[1];
+
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", {
+ key: id,
+ className: "changelog__entry__row"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog__change--prev"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "country",
+ data: country.prev.country
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "role",
+ data: country.prev.role
+ }))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog__change--new"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "country",
+ data: country.new.country
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "role",
+ data: country.new.role
+ }))));
+ }), Object.entries(data.diff_list.programs).length > 0 && Object.entries(data.diff_list.programs).map(function (_ref6) {
+ var _ref7 = _slicedToArray(_ref6, 2),
+ id = _ref7[0],
+ program = _ref7[1];
+
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", {
+ key: id,
+ className: "changelog__entry__row"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog__change--prev"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "program",
+ data: program.prev.program
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "country",
+ data: program.prev.country
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "role",
+ data: program.prev.role
+ }))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog__change--new"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "program",
+ data: program.new.program
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "country",
+ data: program.new.country
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "role",
+ data: program.new.role
+ }))));
+ }));
+ } else {
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", {
+ className: "changelog__entry__row"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
+ className: "text-nowrap"
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog__change--prev"
+ }, data.diff_list.map(function (changeset, id) {
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ key: id,
+ name: changeset.name,
+ data: changeset.prev
+ });
+ }))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog__change--new"
+ }, data.diff_list.map(function (changeset, id) {
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ key: id,
+ name: changeset.name,
+ data: changeset.new
+ });
+ }))));
+ }
+};
+
+var ChangeLogEntry = function ChangeLogEntry(_ref8) {
+ var data = _ref8.data;
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tbody", {
+ className: "changelog__entry",
+ key: data.id
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeLogEntryHeader, {
+ data: data
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeLogEntryRow, {
+ data: data
+ }));
+};
+
+var ChangeLog = function ChangeLog(_ref9) {
+ var data = _ref9.data;
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("table", {
+ className: "table table-sm bg-white table-bordered text-small changelog"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("thead", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap"
+ }, gettext("Date")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap"
+ }, gettext("Admin")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap"
+ }, gettext("Change Type")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap td--half-stretch"
+ }, gettext("Previous Entry")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap td--half-stretch"
+ }, gettext("New Entry")))), data.map(function (entry, id) {
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeLogEntry, {
+ key: id,
+ data: entry
+ });
+ }));
+};
+
+/* harmony default export */ __webpack_exports__["default"] = (ChangeLog);
+
+/***/ }),
+
/***/ "P05O":
/*!***********************************************************************************!*\
!*** ./js/pages/tola_management_pages/program/components/edit_program_profile.js ***!
@@ -2450,4 +2591,4 @@ function () {
/***/ })
},[["1faY","runtime","vendors"]]]);
-//# sourceMappingURL=tola_management_program-feca61b7873f2fd0e205.js.map
\ No newline at end of file
+//# sourceMappingURL=tola_management_program-1c0ce8637a72447286c3.js.map
\ No newline at end of file
diff --git a/build/dev-dist/tola_management_program-1c0ce8637a72447286c3.js.map b/build/dev-dist/tola_management_program-1c0ce8637a72447286c3.js.map
new file mode 100644
index 00000000..340a9450
--- /dev/null
+++ b/build/dev-dist/tola_management_program-1c0ce8637a72447286c3.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"tola_management_program-1c0ce8637a72447286c3.js","sources":["webpack:///./js/pages/tola_management_pages/program/index.js","webpack:///./js/components/virtualized-react-select.js","webpack:///./js/pages/tola_management_pages/program/components/program_history.js","webpack:///./js/components/loading-spinner.js","webpack:///./js/pages/tola_management_pages/program/api.js","webpack:///./js/components/expander.js","webpack:///./js/components/changelog.js","webpack:///./js/pages/tola_management_pages/program/components/edit_program_profile.js","webpack:///./js/components/pagination.js","webpack:///./js/components/management-table.js","webpack:///./js/api.js","webpack:///./js/components/checkboxed-multi-select.js","webpack:///./js/pages/tola_management_pages/program/views.js","webpack:///./js/pages/tola_management_pages/program/components/program_editor.js","webpack:///./js/components/folding-sidebar.js","webpack:///./js/pages/tola_management_pages/program/models.js"],"sourcesContent":["import React from 'react';\nimport ReactDOM from 'react-dom';\nimport {ProgramStore} from './models';\nimport {IndexView} from './views';\nimport api from './api';\n\n/*\n * Model/Store setup\n */\n\nconst {\n country_filter,\n organization_filter,\n users_filter,\n allCountries,\n countries,\n organizations,\n users,\n programFilterPrograms,\n sectors,\n} = jsContext\n\n/* formatting filters to be used by the ProgramStore */\nconst makeCountryOptions = (country_ids) => country_ids.map(id => countries[id]).map(country => ({label: country.name, value: country.id}))\nconst makeOrganizationOptions = (org_ids) => org_ids.map(id => organizations[id]).map(org => ({label: org.name, value: org.id}))\nconst makeUserOptions = (user_ids) => user_ids.map(id => users[id]).map(user => ({label: user.name, value: user.id}))\n\nconst filters = {\n countries: makeCountryOptions(country_filter),\n organizations: makeOrganizationOptions(organization_filter),\n users: makeUserOptions(users_filter)\n}\n\nconst initialData = {\n countries,\n allCountries,\n organizations,\n programFilterPrograms,\n sectors,\n filters,\n users\n}\nconst store = new ProgramStore(\n api,\n initialData,\n);\n\n\nReactDOM.render(\n ,\n document.querySelector('#app_root')\n);\n","import React from 'react'\nimport {List, AutoSizer, CellMeasurer, CellMeasurerCache} from 'react-virtualized'\nimport Select, {components} from 'react-select'\n\nexport class VirtualizedMenuList extends React.PureComponent {\n constructor(props) {\n super(props)\n this.cache = new CellMeasurerCache({\n fixedWidth: true,\n defaultHeight: 35,\n })\n this.filter_val = \"\"\n }\n\n render() {\n const {options, children, maxHeight, getValue, selectProps} = this.props\n const rowCount = children.length || 0\n\n //gotta be a way to improve this. it's ok after the first couple of\n //characters search, but it's slow prior to that\n if(selectProps.inputValue !== this.filter_val) {\n this.filter_val = selectProps.inputValue\n this.cache.clearAll()\n }\n\n return (\n \n
\n
\n {({width, height}) => {\n return No selections available
}\n rowRenderer={\n ({index, parent, key, style}) =>\n \n {children[index]}
\n \n }/>\n }}\n
\n
\n
\n )\n }\n}\n\nconst VirtualizedSelect = props => (\n \n)\n\nexport default VirtualizedSelect\n","import React from 'react'\nimport Select from 'react-select'\nimport {AutoSizer, Table, Column, CellMeasurer, CellMeasurerCache} from 'react-virtualized'\nimport { observer } from 'mobx-react';\nimport Expander from 'components/expander'\nimport ChangeLog from 'components/changelog'\n\nconst status_options = [\n {value: 'Funded', label: 'Funded'},\n {value: 'Completed', label: 'Completed'}\n]\n\n@observer\nexport class ProgramHistory extends React.Component {\n\n constructor(props) {\n super(props)\n const {program_data} = props\n this.state = {\n managed_status: Object.assign({}, program_data),\n original_status: Object.assign({}, program_data)\n }\n }\n\n onStatusChange(selection) {\n let value = selection.value\n this.setState({\n managed_status: Object.assign(this.state.managed_status, {'funding_status': value})\n })\n }\n\n onSave() {\n const program_id = this.state.original_status.id\n const program_data = this.state.managed_status\n this.props.onSave(this.state.original_status.id, this.state.managed_status)\n }\n\n onReset() {\n this.setState({\n managed_status: this.state.original_status,\n })\n }\n\n render() {\n const {history} = this.props\n const currentStatusSelection = status_options.find(x=> x.value == this.state.managed_status.funding_status)\n return \n
{this.props.program_data.name ? this.props.program_data.name+': ' : ''}{gettext(\"Status and History\")} \n
\n {gettext(\"Program Status\")}* \n this.onStatusChange(new_value)}\n />\n
\n
\n this.onSave()}>{gettext(\"Save Changes\")} \n this.onReset()}>{gettext(\"Reset\")} \n
\n\n
\n\n
\n }\n}\n\nexport default ProgramHistory\n","\nimport React from 'react'\n\nconst LoadingSpinner = ({children, isLoading, className, ...props}) => {\n const loading = (isLoading)?'loading':''\n return \n}\n\nexport default LoadingSpinner\n","import {api} from '../../../api';\n\n\nexport const fetchPrograms = (page, filters) => {\n return api.get('/tola_management/program/', {params: {page: page, ...filters}}).then(response => {\n let data = response.data\n let results = data.results\n let total_results = data.count\n let total_pages = data.page_count\n let next_page = data.next\n let prev_page = data.previous\n\n return {\n results,\n total_results,\n total_pages,\n next_page,\n prev_page,\n }\n })\n}\n\nexport const fetchProgramsForFilter = (filters) => {\n return api.get('/tola_management/program/program_filter_options', {params: {...filters}})\n}\n\nexport const createProgram = (data) => api.post('/tola_management/program/', data)\n\nexport const updateProgram = (id, data) => api.put(`/tola_management/program/${id}/`, data)\n\nexport const updateProgramFundingStatusBulk = (ids, funding_status) => {\n return api.post('/tola_management/program/bulk_update_status/', {ids, funding_status})\n}\n\nexport const fetchProgramHistory = (id) => api.get(`/tola_management/program/${id}/history/`)\n\n\nexport default {\n fetchPrograms,\n fetchProgramsForFilter,\n fetchProgramHistory,\n createProgram,\n updateProgram,\n updateProgramFundingStatusBulk,\n}\n","import React from 'react'\n\nclass Expander extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n expanded: false,\n overflowing: false,\n }\n this.ref = React.createRef()\n }\n\n componentDidMount() {\n if(this.ref.current.scrollHeight > this.ref.current.clientHeight) {\n this.setState({overflowing: true})\n }\n }\n\n toggleExpanded(e) {\n e.preventDefault()\n this.setState({\n expanded: !this.state.expanded\n })\n }\n\n render() {\n return \n
\n {this.props.children}\n
\n {this.state.overflowing &&\n
\n }\n
\n }\n}\n\nexport default Expander\n","import React from 'react'\n\nconst ChangeField = ({name, data}) => {\n return \n {name} : {(data != undefined && data != null)?data.toString():'N/A'}\n
\n}\n\nconst ChangeLogEntryHeader = ({data}) => {\n return {/* TODO: apply is-expanded dynamically */}\n {data.date} \n {data.admin_user} \n {data.change_type} \n \n \n \n}\n\nconst ChangeLogEntryRow = ({data}) => {\n if (data.change_type == 'user_programs_updated') {\n // Create multiple row for program/country changes:\n return \n {Object.entries(data.diff_list.countries).length > 0 &&\n Object.entries(data.diff_list.countries).map(([id, country]) =>\n \n \n \n \n \n \n \n \n
\n \n \n \n \n \n
\n \n \n )\n }\n {Object.entries(data.diff_list.programs).length > 0 &&\n Object.entries(data.diff_list.programs).map(([id, program]) =>\n \n \n \n \n \n \n \n \n \n
\n \n \n \n \n \n \n
\n \n \n )\n }\n \n } else {\n return \n \n \n \n \n \n {data.diff_list.map((changeset, id) =>\n \n )}\n
\n \n \n \n {data.diff_list.map((changeset, id) =>\n \n )}\n
\n \n \n }\n}\n\nconst ChangeLogEntry = ({data}) => {\n return \n \n \n \n}\n\nconst ChangeLog = ({data}) => {\n return \n \n \n {gettext(\"Date\")} \n {gettext(\"Admin\")} \n {gettext(\"Change Type\")} \n {gettext(\"Previous Entry\")} \n {gettext(\"New Entry\")} \n \n \n {data.map((entry, id) =>\n \n )}\n
\n}\n\nexport default ChangeLog\n","import React from 'react'\nimport Select from 'react-select'\nimport { observer } from \"mobx-react\"\nimport CheckboxedMultiSelect from 'components/checkboxed-multi-select'\nimport classNames from 'classnames'\n\n\n const fundingStatusOptions = [\n {value: 'Funded', label: gettext('Funded')},\n {value: 'Completed', label: gettext('Completed')},\n]\n\nconst ErrorFeedback = observer(({errorMessages}) => {\n if (!errorMessages) {\n return null\n }\n return (\n \n {errorMessages.map((message, index) =>\n {message} \n )}\n
\n )\n})\n@observer\nexport default class EditProgramProfile extends React.Component {\n constructor(props) {\n super(props)\n const {program_data} = props\n\n this.state = {\n original_data: Object.assign({}, program_data),\n managed_data: Object.assign({}, program_data)\n }\n }\n\n\n save(e) {\n e.preventDefault()\n const program_id = this.props.program_data.id\n const program_data = this.state.managed_data\n this.props.onUpdate(program_id, program_data)\n }\n\n saveNew(e) {\n e.preventDefault()\n const program_data = this.state.managed_data\n this.props.onCreate(program_data)\n }\n\n updateFormField(fieldKey, val) {\n this.setState({\n managed_data: Object.assign(this.state.managed_data, {[fieldKey]: val})\n })\n }\n\n resetForm() {\n this.setState({\n managed_data: Object.assign({}, this.state.original_data)\n })\n }\n\n formErrors(fieldKey) {\n return this.props.errors[fieldKey]\n }\n\n render() {\n const formdata = this.state.managed_data\n const selectedFundingStatus = fundingStatusOptions.find(x=> x.value == formdata.funding_status)\n const selectedCountries = formdata.country.map(x=>this.props.countryOptions.find(y=>y.value==x))\n const selectedSectors = formdata.sector.map(x=>this.props.sectorOptions.find(y=>y.value==x))\n return (\n \n
{this.props.program_data.name ? this.props.program_data.name+': ' : ''}{gettext(\"Profile\")} \n
\n \n {gettext(\"Program name\")}* \n this.updateFormField('name', e.target.value) }\n className={classNames('form-control', { 'is-invalid': this.formErrors('name') })}\n id=\"program-name-input\"\n required />\n \n
\n \n {gettext(\"GAIT ID\")} \n this.updateFormField('gaitid', e.target.value) }\n className={classNames('form-control', { 'is-invalid': this.formErrors('gaitid') })}\n id=\"program-gait-input\"\n disabled={!this.props.new}\n />\n \n
\n \n {gettext(\"Fund Code\")} \n this.updateFormField('fundCode', e.target.value) }\n className={classNames('form-control', { 'is-invalid': this.formErrors('fundCode') })}\n id=\"program-fund-code-input\"\n disabled={true}\n />\n \n
\n \n {gettext(\"Description\")} \n this.updateFormField('description', e.target.value) }\n className={classNames('form-control', { 'is-invalid': this.formErrors('description') })}\n id=\"program-description-input\"\n />\n \n
\n \n {gettext(\"Countries\")}* \n this.updateFormField('country', e.map(x=>x.value)) }\n className={classNames('react-select', {'is-invalid': this.formErrors('country')})}\n id=\"program-country-input\"\n />\n \n
\n \n {gettext(\"Sectors\")} \n this.updateFormField('sector', e.map(x=>x.value)) }\n className={classNames('react-select', {'is-invalid': this.formErrors('sector')})}\n id=\"program-sectors-input\"\n />\n \n
\n \n {gettext(\"Funding Status\")}* \n this.updateFormField('funding_status', e.value) }\n isSearchable={false}\n className={classNames('react-select', {'is-invalid': this.formErrors('funding_status')})}\n id=\"program-funding-status-input\"\n />\n \n
\n {this.props.new &&\n \n this.saveNew(e)}>{gettext(\"Save Changes\")} \n {/* this.saveNewAndAddAnother(e)}>Save And Add Another */}\n this.resetForm()}>{gettext(\"Reset\")} \n
\n }\n {!this.props.new &&\n \n this.save(e)}>{gettext(\"Save Changes\")} \n this.resetForm()}>{gettext(\"Reset\")} \n
\n }\n \n
\n )\n }\n}\n","import React from 'react'\nimport ReactPaginate from 'react-paginate'\nimport { observer } from \"mobx-react\"\n\n/***\n Props:\n\n - pageCount: total number of pages\n - initialPage: which page should be highlighted as active initially\n - onPageChange: a function to receive the newly selected page\n*/\nconst Pagination = (props) => {\n return \n}\n\nexport default Pagination\n","import { observer } from \"mobx-react\"\nimport React from 'react';\nimport classNames from 'classnames';\n\n// TODO: \"size\" is no longer used\nconst ColumnComponent = ({className, size, ...props}) => {props.children} \n\n// TODO: this is redundant with ColumnComponent\nconst HeaderColumnComponent = ({className, size, ...props}) => {props.children} \n\nconst InnerRowComponent = ({className, ...props}) => {props.children} \n\n// TODO: this is redundant with InnerRowComponent\nconst HeaderRowComponent = ({className, ...props}) => {props.children} \n\n/***\n A wrapper for the rendering of the given row renderer, it takes and expando\n renderer used to render expanded content\n\n Props:\n - expanded: whether the expando content is shown or not\n - Expando: The content to render when the expando is shown\n*/\nconst RowComponent = observer(({className, expanded, Expando, ...props}) => {\n if(Expando) {\n const ObservedExpando = observer(Expando)\n return \n {props.children} \n {expanded && }\n \n } else {\n return \n {props.children} \n \n }\n})\nconst ExpandoWrapper = ({className, ...props}) => {props.children} \n\nconst RowList = observer(({data, Row, keyField, ...props}) => {\n const ObservedRow = observer(Row)\n return data.map(row_data => )\n})\n\n/*\n Props:\n\n - HeaderRow: a function to render the header row. it receives a component\n prop to render the header column and row\n\n - Row: a function used to render each row. it receives a component prop to\n render the row (see RowComponent), it receives the relevant data for that\n row as a prop: data\n\n - data: the dataset used to render the table, it must be an array\n\n - keyField: field to use for key on rows and expando checking\n\n */\nconst ManagementTable = observer(({HeaderRow, className, ...props}) => {\n const ObservedHeaderRow = observer(HeaderRow)\n return \n})\nexport default ManagementTable\n","import axios from 'axios';\n\nexport const api = axios.create({\n withCredentials: true,\n baseURL: '/api/',\n headers: {\n \"X-CSRFToken\": document.cookie.replace(/(?:(?:^|.*;\\s*)csrftoken\\s*\\=\\s*([^;]*).*$)|^.*$/, \"$1\")\n }\n});\n","import React from 'react'\nimport Select, {components} from 'react-select'\nimport {VirtualizedMenuList as MenuList} from './virtualized-react-select'\nimport {observer} from 'mobx-react'\n\nconst Option = props => {\n return (components.Option &&\n \n {\n //we can let the outer component manage state\n }}\n />\n \n {props.data.label}\n \n )\n}\n\nconst CheckboxedMultiSelect = observer(props => (\n \n))\n\nexport default CheckboxedMultiSelect\n","import React from 'react'\nimport { observer } from \"mobx-react\"\nimport Select from 'react-select'\nimport CheckboxedMultiSelect from 'components/checkboxed-multi-select'\nimport ManagementTable from 'components/management-table'\nimport Pagination from 'components/pagination'\nimport ProgramEditor from './components/program_editor'\nimport EditProgramProfile from './components/edit_program_profile'\nimport ProgramHistory from './components/program_history'\nimport LoadingSpinner from 'components/loading-spinner'\nimport FoldingSidebar from 'components/folding-sidebar'\n\nconst UserFilter = observer(({store, filterOptions}) => {\n return \n {gettext(\"Users\")} \n store.changeFilter('users', e)}\n placeholder={gettext(\"None Selected\")}\n id=\"users_filter\" />\n
\n})\n\nconst CountryFilter = observer(({store, filterOptions}) => {\n return \n {gettext(\"Countries\")} \n store.changeFilter('countries', e)}\n placeholder={gettext(\"None Selected\")}\n id=\"countries_filter\" />\n
\n})\n\nconst OrganizationFilter = observer(({store, filterOptions}) => {\n return \n {gettext(\"Organizations\")} \n store.changeFilter('organizations', e)}\n placeholder={gettext(\"None Selected\")}\n id=\"organizations_filter\" />\n
\n})\n\nconst SectorFilter = observer(({store, filterOptions}) => {\n return \n {gettext(\"Sectors\")} \n store.changeFilter('sectors', e)}\n placeholder={gettext(\"None Selected\")}\n id=\"sector-filter\" />\n
\n})\n\nconst ProgramStatusFilter = observer(({store}) => {\n const statusFilterOptions = [\n {value: 'Active', label: gettext('Active')},\n {value: 'Closed', label: gettext('Closed')},\n ]\n return \n {gettext(\"Status\")} \n store.changeFilter('programStatus', e)}\n placeholder={gettext(\"None Selected\")}\n id=\"program-status-filter\" />\n
\n})\n\nconst ProgramFilter = observer(({store, filterOptions}) => {\n return \n {gettext(\"Programs\")} \n store.changeFilter('programs', e)}\n placeholder={gettext(\"None Selected\")}\n id=\"programs-filter\" />\n
\n})\n\n\nclass BulkActions extends React.Component {\n constructor(props) {\n super(props)\n this.active_child = React.createRef()\n this.state = {\n current_action: null,\n current_vals: []\n }\n }\n\n onActionChanged(new_action) {\n this.setState({\n current_action: new_action.value\n })\n }\n\n onChange(vals) {\n this.setState({\n current_vals: vals\n })\n }\n\n onApply() {\n const selected = this.props.secondaryOptions[this.state.current_action]\n if(selected) {\n selected.onApply(this.state.current_vals)\n }\n }\n\n render() {\n const selected = this.props.secondaryOptions[this.state.current_action]\n const SecondaryComponent = selected && selected.component\n return \n
\n o.value == this.state.current_action)}\n options={this.props.primaryOptions} onChange={(val) => this.onActionChanged(val)} />\n
\n {selected &&\n
\n this.onChange(vals)}/>\n
\n }\n {!selected &&\n
\n \n
\n }\n
this.onApply()}>{gettext(\"Apply\")} \n
\n }\n}\n\n\nexport const IndexView = observer(\n ({store}) => {\n\n const allCountryOptions = Object.entries(store.allCountries).map(([id, country]) => ({value: country.id, label: country.name}))\n const countryFilterOptions = Object.entries(store.countries).map(([id, country]) => ({value: country.id, label: country.name}))\n const organizationFilterOptions = Object.entries(store.organizations).map(([id, org]) => ({value: org.id, label: org.name}))\n const sectorFilterOptions = store.sectors.map(x => ({value: x.id, label: x.name}))\n const programFilterOptions = Object.entries(store.programFilterPrograms).map(([id, program]) => ({value: program.id, label: program.name}))\n const userFilterOptions = Object.entries(store.users).map(([id, user]) => ({value: user.id, label: user.name}))\n const bulkProgramStatusOptions = [\n {value: 'Funded', label: gettext('Funded')},\n {value: 'Completed', label: gettext('Completed')},\n ]\n\n const bulk_actions = {\n primary_options: [\n {label: gettext('Set program status'), value: 'set_program_status'},\n ],\n secondary_options: {\n set_program_status: {\n component: (props) => ,\n onApply: (option) => store.bulkUpdateProgramStatus(option.value)\n },\n }\n }\n\n const organizationColumn = (data) => {\n if (data.organizations) {\n return (\n \n \n { data.onlyOrganizationId ? store.organizations[data.onlyOrganizationId].name : `${data.organizations} organizations` }\n \n )\n }\n return \"---\"\n }\n\n return \n
\n \n
\n
\n
\n
\n
\n
\n
\n store.applyFilters()}>{gettext(\"Apply\")} \n store.clearFilters()}>{gettext(\"Reset\")} \n
\n
\n \n
\n
\n
\n \n \n
\n
{store.program_count ? `${store.program_count} ${gettext(\"programs\")}`:`---`}
\n
\n {store.total_pages &&\n
store.changePage(page)} />\n }\n \n
\n
\n
\n }\n)\n","import React from 'react'\nimport { observer } from \"mobx-react\"\n\n@observer\nexport default class ProgramEditor extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n active_page: 'profile'\n }\n }\n\n updateActivePage(new_page) {\n if(!this.props.new) {\n this.setState({active_page: new_page})\n }\n }\n\n render() {\n const {ProfileSection, HistorySection} = this.props\n\n const profile_active_class = (this.state.active_page == 'profile')?'active':''\n const history_active_class = (this.state.active_page == 'status_and_history')?'active':''\n const new_class = (this.props.new)?'disabled':''\n\n return (\n \n
\n
\n {this.state.active_page == 'profile' &&\n
\n }\n\n {this.state.active_page == 'status_and_history' &&\n
\n }\n
\n
\n )\n }\n}\n","import React from 'react'\n\nclass Expander extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n folded: false,\n }\n }\n\n toggleFolded() {\n this.setState({\n folded: !this.state.folded\n })\n }\n\n render() {\n const {className, ...props} = this.props\n const icon = (this.state.folded)?\"fa-chevron-right\":\"fa-chevron-left\"\n return \n {!this.state.folded &&\n
{this.props.children} \n }\n\n
this.toggleFolded()}>\n \n
\n
\n }\n}\n\nexport default Expander\n","import { observable, computed, action, runInAction } from \"mobx\";\n\n\nexport class ProgramStore {\n\n //filter options\n @observable countries = {}\n @observable allCountries = {}\n @observable organizations = {}\n @observable users = {}\n @observable sectors = []\n\n @observable filters = {\n countries: [],\n organizations: [],\n sectors: [],\n programStatus: null,\n programs: [],\n users: []\n }\n\n @observable programFilterPrograms = []\n @observable programs = []\n @observable program_count = 0\n @observable new_program = null\n @observable fetching_main_listing = false\n @observable current_page = 0\n @observable total_pages = null\n @observable bulk_targets = new Map()\n @observable bulk_targets_all = false\n\n @observable editing_target = null\n @observable editing_errors = {}\n @observable fetching_editing_history = true\n @observable editing_target_history = null\n @observable saving = false\n\n @observable bulk_targets = new Map()\n @observable applying_bulk_updates = false\n @observable bulk_targets_all = false\n\n constructor(\n api,\n initialData,\n ) {\n this.api = api\n Object.assign(this, initialData)\n this.fetchPrograms()\n }\n\n marshalFilters(filters) {\n return Object.entries(filters).reduce((xs, [filterKey, filterValue]) => {\n if (Array.isArray(filterValue)) {\n xs[filterKey] = filterValue.map(x => x.value)\n } else if (filterValue) {\n xs[filterKey] = filterValue.value\n }\n return xs\n }, {})\n }\n\n @action\n fetchPrograms() {\n this.fetching_main_listing = true\n this.api.fetchPrograms(this.current_page + 1, this.marshalFilters(this.filters)).then(results => {\n runInAction(() => {\n this.fetching_main_listing = false\n this.programs = results.results\n this.program_count = results.total_results\n this.total_pages = results.total_pages\n this.next_page =results.next_page\n this.previous_page = results.previous_page\n })\n })\n this.api.fetchProgramsForFilter(this.marshalFilters(this.filters)).then(response => {\n runInAction(() => {\n this.programFilterPrograms = response.data\n })\n })\n\n }\n\n @action\n applyFilters() {\n this.current_page = 0\n this.fetchPrograms()\n }\n\n @action\n changePage(page) {\n if (page.selected == this.current_page) {\n return\n }\n this.current_page = page.selected\n this.bulk_targets = new Map()\n this.bulk_targets_all = false;\n this.fetchPrograms()\n }\n\n @action\n changeFilter(filterKey, value) {\n this.filters = Object.assign(this.filters, {[filterKey]: value})\n }\n\n @action\n clearFilters() {\n let clearFilters = {\n countries: [],\n organizations: [],\n sectors: [],\n programStatus: null,\n programs: [],\n users: []\n }\n this.filters = Object.assign(this.filters, clearFilters);\n }\n\n @action\n toggleEditingTarget(id) {\n if(this.editing_target == 'new') {\n this.programs.shift()\n this.editing_errors = {}\n }\n\n if(this.editing_target == id) {\n this.editing_target = false\n this.editing_errors = {}\n } else {\n this.editing_target = id\n this.fetching_editing_history = true\n this.api.fetchProgramHistory(id).then(resp => {\n runInAction(() => {\n this.fetching_editing_history = false\n this.editing_history = resp.data\n })\n })\n }\n }\n\n updateLocalPrograms(updated) {\n this.programs = this.programs.reduce((acc, current) => {\n if (current.id == updated.id) {\n acc.push(updated)\n } else {\n acc.push(current)\n }\n return acc\n }, [])\n }\n\n onSaveSuccessHandler() {\n PNotify.success({text: gettext(\"Successfully Saved\"), delay: 5000})\n }\n\n onSaveErrorHandler() {\n PNotify.error({text: gettext(\"Saving Failed\"), delay: 5000})\n }\n\n @action\n createProgram() {\n if(this.editing_target == 'new') {\n this.programs.shift()\n }\n\n let new_program_data = {\n id: \"new\",\n name: \"\",\n gaitid: \"\",\n fundcode: \"\",\n funding_status: \"\",\n description: \"\",\n country: [],\n sector: [],\n }\n this.programs.unshift(new_program_data)\n this.editing_target = 'new'\n }\n\n @action\n saveNewProgram(program_data) {\n program_data.id = null\n this.saving = true\n this.api.createProgram(program_data).then(response => {\n runInAction(()=> {\n this.saving = false\n this.editing_target = false\n this.programs.shift()\n this.programs.unshift(response.data)\n })\n }).catch(error => {\n runInAction(()=> {\n let errors = error.response.data\n this.saving = false\n this.editing_errors = errors\n })\n })\n }\n\n @action updateProgram(id, program_data) {\n this.saving = true\n this.api.updateProgram(id, program_data).then(response => {\n runInAction(() => {\n this.saving = false\n this.editing_target = false\n this.updateLocalPrograms(response.data)\n this.onSaveSuccessHandler()\n })\n }).catch((errors) => {\n runInAction(() => {\n this.saving = false\n this.editing_errors = errors.response.data\n this.onSaveErrorHandler()\n })\n })\n }\n\n @action\n toggleBulkTarget(target_id) {\n this.bulk_targets.set(target_id, !this.bulk_targets.get(target_id))\n }\n\n @action\n toggleBulkTargetsAll() {\n this.bulk_targets_all = !this.bulk_targets_all\n this.bulk_targets = new Map(this.programs.map(program => [program.id, this.bulk_targets_all]))\n }\n\n postBulkUpdateLocalPrograms(updatedPrograms) {\n let updatedProgramsById = new Map(updatedPrograms.map(program => [program.id, program]))\n this.programs = this.programs.reduce((acc, current) => {\n let updated = updatedProgramsById.get(current.id)\n if (updated) {\n acc.push(Object.assign(current, updated))\n } else {\n acc.push(current)\n }\n return acc\n }, [])\n }\n\n @action\n bulkUpdateProgramStatus(new_status) {\n let ids = Array.from(this.bulk_targets.entries()).filter(([id, targeted]) => targeted).map(([id, targeted]) => id)\n if (ids.length && new_status) {\n this.applying_bulk_updates = true\n this.api.updateProgramFundingStatusBulk(ids, new_status).then(response => {\n let updatedPrograms = response.data\n runInAction(() => {\n this.postBulkUpdateLocalPrograms(updatedPrograms)\n this.applying_bulk_updates = false\n this.onSaveSuccessHandler()\n })\n }).catch(error => {\n runInAction(() => {\n this.applying_bulk_updates = false\n this.onSaveErrorHandler()\n })\n })\n }\n }\n\n}\n"],"mappings":";;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAEA;;;;AAcA;AATA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAHA;AAMA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAPA;AASA;AAMA;AACA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACjDA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AACA;AAAA;AACA;AACA;AACA;AAFA;AAIA;AANA;AAOA;AACA;AATA;AAAA;AAAA;AAUA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAFA;AARA;AAaA;AAKA;AA5CA;AACA;AADA;AAAA;AACA;AA8CA;AAAA;AAEA;AACA;AADA;AADA;AADA;AACA;AAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3DA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAIA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AADA;AACA;AAAA;AADA;AAGA;AACA;AACA;AAFA;AAHA;AAOA;AACA;AAVA;AAAA;AAAA;AAYA;AACA;AACA;AAAA;AAAA;AADA;AAGA;AAhBA;AAAA;AAAA;AAmBA;AACA;AACA;AACA;AAtBA;AAAA;AAAA;AAyBA;AACA;AADA;AAGA;AA5BA;AAAA;AAAA;AA8BA;AACA;AADA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAJA;AAOA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAGA;AApDA;AACA;AADA;AAAA;AAuDA;;;;;;;;;;;;;;;;;;;;;ACnEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAIA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;ACbA;AAGA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AALA;AAOA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAEA;AAAA;AAAA;AAEA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAAA;AACA;AAEA;AAAA;AAAA;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACrCA;AACA;AACA;;;;;AACA;AAAA;AACA;AADA;AACA;AAAA;AACA;AACA;AACA;AAFA;AAIA;AANA;AAOA;AACA;;;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;;AAEA;AACA;AACA;AACA;AADA;AAGA;;;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;;;;AAlCA;AACA;AAoCA;;;;;;;;;;;;;;;;;;;;;;;ACvCA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AAKA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAEA;AAAA;AAAA;AACA;AADA;AACA;AAAA;AAAA;AAKA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAIA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAdA;AAqBA;AAAA;AAAA;AACA;AADA;AACA;AAAA;AAAA;AAKA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAIA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAhBA;AAuBA;AACA;AAAA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AADA;AAMA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AADA;AAMA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAGA;AACA;AAAA;AAAA;AADA;AAIA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClHA;AACA;AACA;AACA;AACA;AAGA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAGA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AADA;AAKA;AACA;AACA;;;;;AACA;AAAA;AACA;AADA;AACA;AAAA;AADA;AAIA;AACA;AACA;AAFA;AAJA;AAQA;AACA;;;AAEA;AACA;AACA;AACA;AACA;AACA;;;AAEA;AACA;AACA;AACA;AACA;;;AAEA;AACA;AACA;AADA;AAGA;;;AAEA;AACA;AACA;AADA;AAGA;;;AAEA;AACA;AACA;;;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AANA;AAOA;AAAA;AAEA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AANA;AAQA;AAAA;AAEA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AANA;AAQA;AAAA;AAEA;AAAA;AACA;AAAA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAJA;AAMA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AALA;AAOA;AAAA;AAEA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AALA;AAOA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AANA;AAQA;AAAA;AAGA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAMA;;;;AAjJA;AACA;;;;;;;;;;;;;;;;;;;;;AC1BA;AACA;AACA;AAEA;;;;;;;;AAOA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAhBA;AAkBA;AACA;AACA;;;;;;;;;;;;;;;;;;;;;;;;AChCA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAEA;;;;;;;;;;AAQA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AADA;AAIA;AAAA;AAEA;AACA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAEA;;;;;;;;;;;;;;;;AAeA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAEA;AAAA;AAAA;AAIA;AACA;;;;;;;;;;;;ACrEA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AADA;AAHA;;;;;;;;;;;;;;;;;;;;ACFA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AANA;AAYA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAFA;AAJA;AADA;AAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AALA;AAOA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AALA;AAOA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AALA;AAOA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AALA;AAOA;AAEA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AANA;AAQA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AALA;AAOA;AACA;AAEA;;;;;AACA;AAAA;AACA;AADA;AACA;AAAA;AACA;AACA;AACA;AACA;AAFA;AAHA;AAOA;AACA;;;AACA;AACA;AACA;AADA;AAGA;;;AAEA;AACA;AACA;AADA;AAGA;;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;;;AAEA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAHA;AAMA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AACA;AAAA;AAGA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;;;;AAnDA;AACA;AAsDA;AACA;AAEA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAFA;AADA;AAJA;AACA;AAWA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAIA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AALA;AAWA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAGA;AACA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AAPA;AAFA;AAYA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;AALA;AAFA;AAdA;AAFA;AAFA;AA+BA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAKA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAQA;AAAA;AACA;AAAA;AAAA;AAAA;AArDA;AAfA;AA4EA;AAAA;AACA;AAAA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAHA;AASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC1SA;AACA;AACA;AAEA;;;;;AACA;AAAA;AACA;AADA;AACA;AAAA;AACA;AACA;AADA;AAFA;AAKA;AACA;;;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;;;AAEA;AAAA;AACA;AADA;AAAA;AAAA;AAGA;AACA;AACA;AAEA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AADA;AAAA;AADA;AAKA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AADA;AAAA;AADA;AAMA;AAAA;AAWA;;;;AAhDA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACLA;AACA;AACA;;;;;AACA;AAAA;AACA;AADA;AACA;AAAA;AACA;AACA;AADA;AAFA;AAKA;AACA;;;AACA;AACA;AACA;AADA;AAGA;;;AAEA;AAAA;AACA;AADA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAKA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAGA;;;;AA1BA;AACA;AA4BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/BA;AAGA;AAAA;AAAA;AAEA;AAoCA;AAGA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AAAA;AACA;AACA;AACA;AACA;AA9CA;AAAA;AAAA;AAgDA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAxDA;AAAA;AAAA;AA2DA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AA7EA;AAAA;AAAA;AAiFA;AACA;AACA;AAnFA;AAAA;AAAA;AAuFA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AA9FA;AAAA;AAAA;AAkGA;AACA;AAnGA;AAAA;AAAA;AAuGA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAQA;AACA;AAhHA;AAAA;AAAA;AAmHA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAtIA;AAAA;AAAA;AAyIA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAjJA;AAAA;AAAA;AAoJA;AAAA;AAAA;AAAA;AACA;AArJA;AAAA;AAAA;AAwJA;AAAA;AAAA;AAAA;AACA;AAzJA;AAAA;AAAA;AA6JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AARA;AAUA;AACA;AACA;AA7KA;AAAA;AAAA;AAgLA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAjMA;AAAA;AAAA;AAmMA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAnNA;AAAA;AAAA;AAuNA;AACA;AAxNA;AAAA;AAAA;AA2NA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AA9NA;AAAA;AAAA;AAiOA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AA3OA;AAAA;AAAA;AA8OA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAhQA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AACA;AACA;AACA;AACA;AACA;AANA;AATA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;A","sourceRoot":""}
\ No newline at end of file
diff --git a/build/dev-dist/tola_management_program-feca61b7873f2fd0e205.js.map b/build/dev-dist/tola_management_program-feca61b7873f2fd0e205.js.map
deleted file mode 100644
index 240822b8..00000000
--- a/build/dev-dist/tola_management_program-feca61b7873f2fd0e205.js.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"file":"tola_management_program-feca61b7873f2fd0e205.js","sources":["webpack:///./js/pages/tola_management_pages/program/index.js","webpack:///./js/components/virtualized-react-select.js","webpack:///./js/pages/tola_management_pages/program/components/program_history.js","webpack:///./js/components/loading-spinner.js","webpack:///./js/pages/tola_management_pages/program/api.js","webpack:///./js/components/expander.js","webpack:///./js/pages/tola_management_pages/program/components/edit_program_profile.js","webpack:///./js/components/pagination.js","webpack:///./js/components/management-table.js","webpack:///./js/api.js","webpack:///./js/components/checkboxed-multi-select.js","webpack:///./js/pages/tola_management_pages/program/views.js","webpack:///./js/pages/tola_management_pages/program/components/program_editor.js","webpack:///./js/components/folding-sidebar.js","webpack:///./js/pages/tola_management_pages/program/models.js"],"sourcesContent":["import React from 'react';\nimport ReactDOM from 'react-dom';\nimport {ProgramStore} from './models';\nimport {IndexView} from './views';\nimport api from './api';\n\n/*\n * Model/Store setup\n */\n\nconst {\n country_filter,\n organization_filter,\n users_filter,\n allCountries,\n countries,\n organizations,\n users,\n programFilterPrograms,\n sectors,\n} = jsContext\n\n/* formatting filters to be used by the ProgramStore */\nconst makeCountryOptions = (country_ids) => country_ids.map(id => countries[id]).map(country => ({label: country.name, value: country.id}))\nconst makeOrganizationOptions = (org_ids) => org_ids.map(id => organizations[id]).map(org => ({label: org.name, value: org.id}))\nconst makeUserOptions = (user_ids) => user_ids.map(id => users[id]).map(user => ({label: user.name, value: user.id}))\n\nconst filters = {\n countries: makeCountryOptions(country_filter),\n organizations: makeOrganizationOptions(organization_filter),\n users: makeUserOptions(users_filter)\n}\n\nconst initialData = {\n countries,\n allCountries,\n organizations,\n programFilterPrograms,\n sectors,\n filters,\n users\n}\nconst store = new ProgramStore(\n api,\n initialData,\n);\n\n\nReactDOM.render(\n ,\n document.querySelector('#app_root')\n);\n","import React from 'react'\nimport {List, AutoSizer, CellMeasurer, CellMeasurerCache} from 'react-virtualized'\nimport Select, {components} from 'react-select'\n\nexport class VirtualizedMenuList extends React.PureComponent {\n constructor(props) {\n super(props)\n this.cache = new CellMeasurerCache({\n fixedWidth: true,\n defaultHeight: 35,\n })\n this.filter_val = \"\"\n }\n\n render() {\n const {options, children, maxHeight, getValue, selectProps} = this.props\n const rowCount = children.length || 0\n\n //gotta be a way to improve this. it's ok after the first couple of\n //characters search, but it's slow prior to that\n if(selectProps.inputValue !== this.filter_val) {\n this.filter_val = selectProps.inputValue\n this.cache.clearAll()\n }\n\n return (\n \n
\n
\n {({width, height}) => {\n return No selections available
}\n rowRenderer={\n ({index, parent, key, style}) =>\n \n {children[index]}
\n \n }/>\n }}\n
\n
\n
\n )\n }\n}\n\nconst VirtualizedSelect = props => (\n \n)\n\nexport default VirtualizedSelect\n","import React from 'react'\nimport Select from 'react-select'\nimport {AutoSizer, Table, Column, CellMeasurer, CellMeasurerCache} from 'react-virtualized'\nimport { observer } from 'mobx-react';\nimport Expander from 'components/expander'\n\nconst status_options = [\n {value: 'Funded', label: 'Funded'},\n {value: 'Completed', label: 'Completed'}\n]\n\nconst ChangesetEntry = ({name, type, data}) => {\n return {name} : {(data != undefined && data != null)?data.toString():'N/A'}
\n}\n\n@observer\nexport class ProgramHistory extends React.Component {\n\n constructor(props) {\n super(props)\n const {program_data} = props\n this.state = {\n managed_status: Object.assign({}, program_data),\n original_status: Object.assign({}, program_data)\n }\n }\n\n onStatusChange(selection) {\n let value = selection.value\n this.setState({\n managed_status: Object.assign(this.state.managed_status, {'funding_status': value})\n })\n }\n\n onSave() {\n const program_id = this.state.original_status.id\n const program_data = this.state.managed_status\n this.props.onSave(this.state.original_status.id, this.state.managed_status)\n }\n\n onReset() {\n this.setState({\n managed_status: this.state.original_status,\n })\n }\n\n render() {\n const {history} = this.props\n const currentStatusSelection = status_options.find(x=> x.value == this.state.managed_status.funding_status)\n return \n
{this.props.program_data.name ? this.props.program_data.name+': ' : ''}{gettext(\"Status and History\")} \n
\n {gettext(\"Program Status\")}* \n this.onStatusChange(new_value)}\n />\n
\n
\n this.onSave()}>{gettext(\"Save Changes\")} \n this.onReset()}>{gettext(\"Reset\")} \n
\n
\n \n \n {gettext(\"Date\")} \n {gettext(\"Admin User\")} \n {gettext(\"Change Type\")} \n {gettext(\"Previous Entry\")} \n {gettext(\"New Entry\")} \n \n \n \n {this.props.history.map(entry => \n {entry.date} \n {entry.admin_user} \n {entry.change_type} \n \n \n {entry.diff_list.map(changeset => {\n return \n })}\n \n \n \n \n {entry.diff_list.map(changeset => {\n return \n })}\n \n \n )}\n \n
\n
\n }\n}\n\nexport default ProgramHistory\n","\nimport React from 'react'\n\nconst LoadingSpinner = ({children, isLoading, className, ...props}) => {\n const loading = (isLoading)?'loading':''\n return \n}\n\nexport default LoadingSpinner\n","import {api} from '../../../api';\n\n\nexport const fetchPrograms = (page, filters) => {\n return api.get('/tola_management/program/', {params: {page: page, ...filters}}).then(response => {\n let data = response.data\n let results = data.results\n let total_results = data.count\n let total_pages = data.page_count\n let next_page = data.next\n let prev_page = data.previous\n\n return {\n results,\n total_results,\n total_pages,\n next_page,\n prev_page,\n }\n })\n}\n\nexport const fetchProgramsForFilter = (filters) => {\n return api.get('/tola_management/program/program_filter_options', {params: {...filters}})\n}\n\nexport const createProgram = (data) => api.post('/tola_management/program/', data)\n\nexport const updateProgram = (id, data) => api.put(`/tola_management/program/${id}/`, data)\n\nexport const updateProgramFundingStatusBulk = (ids, funding_status) => {\n return api.post('/tola_management/program/bulk_update_status/', {ids, funding_status})\n}\n\nexport const fetchProgramHistory = (id) => api.get(`/tola_management/program/${id}/history/`)\n\n\nexport default {\n fetchPrograms,\n fetchProgramsForFilter,\n fetchProgramHistory,\n createProgram,\n updateProgram,\n updateProgramFundingStatusBulk,\n}\n","import React from 'react'\n\nclass Expander extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n expanded: false,\n overflowing: false,\n }\n this.ref = React.createRef()\n }\n\n componentDidMount() {\n if(this.ref.current.scrollHeight > this.ref.current.clientHeight) {\n this.setState({overflowing: true})\n }\n }\n\n toggleExpanded(e) {\n e.preventDefault()\n this.setState({\n expanded: !this.state.expanded\n })\n }\n\n render() {\n return \n
\n {this.props.children}\n
\n {this.state.overflowing &&\n
\n }\n
\n }\n}\n\nexport default Expander\n","import React from 'react'\nimport Select from 'react-select'\nimport { observer } from \"mobx-react\"\nimport CheckboxedMultiSelect from 'components/checkboxed-multi-select'\nimport classNames from 'classnames'\n\n\n const fundingStatusOptions = [\n {value: 'Funded', label: gettext('Funded')},\n {value: 'Completed', label: gettext('Completed')},\n]\n\nconst ErrorFeedback = observer(({errorMessages}) => {\n if (!errorMessages) {\n return null\n }\n return (\n \n {errorMessages.map((message, index) =>\n {message} \n )}\n
\n )\n})\n@observer\nexport default class EditProgramProfile extends React.Component {\n constructor(props) {\n super(props)\n const {program_data} = props\n\n this.state = {\n original_data: Object.assign({}, program_data),\n managed_data: Object.assign({}, program_data)\n }\n }\n\n\n save(e) {\n e.preventDefault()\n const program_id = this.props.program_data.id\n const program_data = this.state.managed_data\n this.props.onUpdate(program_id, program_data)\n }\n\n saveNew(e) {\n e.preventDefault()\n const program_data = this.state.managed_data\n this.props.onCreate(program_data)\n }\n\n updateFormField(fieldKey, val) {\n this.setState({\n managed_data: Object.assign(this.state.managed_data, {[fieldKey]: val})\n })\n }\n\n resetForm() {\n this.setState({\n managed_data: Object.assign({}, this.state.original_data)\n })\n }\n\n formErrors(fieldKey) {\n return this.props.errors[fieldKey]\n }\n\n render() {\n const formdata = this.state.managed_data\n const selectedFundingStatus = fundingStatusOptions.find(x=> x.value == formdata.funding_status)\n const selectedCountries = formdata.country.map(x=>this.props.countryOptions.find(y=>y.value==x))\n const selectedSectors = formdata.sector.map(x=>this.props.sectorOptions.find(y=>y.value==x))\n return (\n \n
{this.props.program_data.name ? this.props.program_data.name+': ' : ''}{gettext(\"Profile\")} \n
\n \n {gettext(\"Program name\")}* \n this.updateFormField('name', e.target.value) }\n className={classNames('form-control', { 'is-invalid': this.formErrors('name') })}\n id=\"program-name-input\"\n required />\n \n
\n \n {gettext(\"GAIT ID\")} \n this.updateFormField('gaitid', e.target.value) }\n className={classNames('form-control', { 'is-invalid': this.formErrors('gaitid') })}\n id=\"program-gait-input\"\n disabled={!this.props.new}\n />\n \n
\n \n {gettext(\"Fund Code\")} \n this.updateFormField('fundCode', e.target.value) }\n className={classNames('form-control', { 'is-invalid': this.formErrors('fundCode') })}\n id=\"program-fund-code-input\"\n disabled={true}\n />\n \n
\n \n {gettext(\"Description\")} \n this.updateFormField('description', e.target.value) }\n className={classNames('form-control', { 'is-invalid': this.formErrors('description') })}\n id=\"program-description-input\"\n />\n \n
\n \n {gettext(\"Countries\")}* \n this.updateFormField('country', e.map(x=>x.value)) }\n className={classNames('react-select', {'is-invalid': this.formErrors('country')})}\n id=\"program-country-input\"\n />\n \n
\n \n {gettext(\"Sectors\")} \n this.updateFormField('sector', e.map(x=>x.value)) }\n className={classNames('react-select', {'is-invalid': this.formErrors('sector')})}\n id=\"program-sectors-input\"\n />\n \n
\n \n {gettext(\"Funding Status\")}* \n this.updateFormField('funding_status', e.value) }\n isSearchable={false}\n className={classNames('react-select', {'is-invalid': this.formErrors('funding_status')})}\n id=\"program-funding-status-input\"\n />\n \n
\n {this.props.new &&\n \n this.saveNew(e)}>{gettext(\"Save Changes\")} \n {/* this.saveNewAndAddAnother(e)}>Save And Add Another */}\n this.resetForm()}>{gettext(\"Reset\")} \n
\n }\n {!this.props.new &&\n \n this.save(e)}>{gettext(\"Save Changes\")} \n this.resetForm()}>{gettext(\"Reset\")} \n
\n }\n \n
\n )\n }\n}\n","import React from 'react'\nimport ReactPaginate from 'react-paginate'\nimport { observer } from \"mobx-react\"\n\n/***\n Props:\n\n - pageCount: total number of pages\n - initialPage: which page should be highlighted as active initially\n - onPageChange: a function to receive the newly selected page\n*/\nconst Pagination = (props) => {\n return \n}\n\nexport default Pagination\n","import { observer } from \"mobx-react\"\nimport React from 'react';\nimport classNames from 'classnames';\n\n// TODO: \"size\" is no longer used\nconst ColumnComponent = ({className, size, ...props}) => {props.children} \n\n// TODO: this is redundant with ColumnComponent\nconst HeaderColumnComponent = ({className, size, ...props}) => {props.children} \n\nconst InnerRowComponent = ({className, ...props}) => {props.children} \n\n// TODO: this is redundant with InnerRowComponent\nconst HeaderRowComponent = ({className, ...props}) => {props.children} \n\n/***\n A wrapper for the rendering of the given row renderer, it takes and expando\n renderer used to render expanded content\n\n Props:\n - expanded: whether the expando content is shown or not\n - Expando: The content to render when the expando is shown\n*/\nconst RowComponent = observer(({className, expanded, Expando, ...props}) => {\n if(Expando) {\n const ObservedExpando = observer(Expando)\n return \n {props.children} \n {expanded && }\n \n } else {\n return \n {props.children} \n \n }\n})\nconst ExpandoWrapper = ({className, ...props}) => {props.children} \n\nconst RowList = observer(({data, Row, keyField, ...props}) => {\n const ObservedRow = observer(Row)\n return data.map(row_data => )\n})\n\n/*\n Props:\n\n - HeaderRow: a function to render the header row. it receives a component\n prop to render the header column and row\n\n - Row: a function used to render each row. it receives a component prop to\n render the row (see RowComponent), it receives the relevant data for that\n row as a prop: data\n\n - data: the dataset used to render the table, it must be an array\n\n - keyField: field to use for key on rows and expando checking\n\n */\nconst ManagementTable = observer(({HeaderRow, className, ...props}) => {\n const ObservedHeaderRow = observer(HeaderRow)\n return \n})\nexport default ManagementTable\n","import axios from 'axios';\n\nexport const api = axios.create({\n withCredentials: true,\n baseURL: '/api/',\n headers: {\n \"X-CSRFToken\": document.cookie.replace(/(?:(?:^|.*;\\s*)csrftoken\\s*\\=\\s*([^;]*).*$)|^.*$/, \"$1\")\n }\n});\n","import React from 'react'\nimport Select, {components} from 'react-select'\nimport {VirtualizedMenuList as MenuList} from './virtualized-react-select'\nimport {observer} from 'mobx-react'\n\nconst Option = props => {\n return (components.Option &&\n \n {\n //we can let the outer component manage state\n }}\n />\n \n {props.data.label}\n \n )\n}\n\nconst CheckboxedMultiSelect = observer(props => (\n \n))\n\nexport default CheckboxedMultiSelect\n","import React from 'react'\nimport { observer } from \"mobx-react\"\nimport Select from 'react-select'\nimport CheckboxedMultiSelect from 'components/checkboxed-multi-select'\nimport ManagementTable from 'components/management-table'\nimport Pagination from 'components/pagination'\nimport ProgramEditor from './components/program_editor'\nimport EditProgramProfile from './components/edit_program_profile'\nimport ProgramHistory from './components/program_history'\nimport LoadingSpinner from 'components/loading-spinner'\nimport FoldingSidebar from 'components/folding-sidebar'\n\nconst UserFilter = observer(({store, filterOptions}) => {\n return \n {gettext(\"Users\")} \n store.changeFilter('users', e)}\n placeholder={gettext(\"None Selected\")}\n id=\"users_filter\" />\n
\n})\n\nconst CountryFilter = observer(({store, filterOptions}) => {\n return \n {gettext(\"Countries\")} \n store.changeFilter('countries', e)}\n placeholder={gettext(\"None Selected\")}\n id=\"countries_filter\" />\n
\n})\n\nconst OrganizationFilter = observer(({store, filterOptions}) => {\n return \n {gettext(\"Organizations\")} \n store.changeFilter('organizations', e)}\n placeholder={gettext(\"None Selected\")}\n id=\"organizations_filter\" />\n
\n})\n\nconst SectorFilter = observer(({store, filterOptions}) => {\n return \n {gettext(\"Sectors\")} \n store.changeFilter('sectors', e)}\n placeholder={gettext(\"None Selected\")}\n id=\"sector-filter\" />\n
\n})\n\nconst ProgramStatusFilter = observer(({store}) => {\n const statusFilterOptions = [\n {value: 'Active', label: gettext('Active')},\n {value: 'Closed', label: gettext('Closed')},\n ]\n return \n {gettext(\"Status\")} \n store.changeFilter('programStatus', e)}\n placeholder={gettext(\"None Selected\")}\n id=\"program-status-filter\" />\n
\n})\n\nconst ProgramFilter = observer(({store, filterOptions}) => {\n return \n {gettext(\"Programs\")} \n store.changeFilter('programs', e)}\n placeholder={gettext(\"None Selected\")}\n id=\"programs-filter\" />\n
\n})\n\n\nclass BulkActions extends React.Component {\n constructor(props) {\n super(props)\n this.active_child = React.createRef()\n this.state = {\n current_action: null,\n current_vals: []\n }\n }\n\n onActionChanged(new_action) {\n this.setState({\n current_action: new_action.value\n })\n }\n\n onChange(vals) {\n this.setState({\n current_vals: vals\n })\n }\n\n onApply() {\n const selected = this.props.secondaryOptions[this.state.current_action]\n if(selected) {\n selected.onApply(this.state.current_vals)\n }\n }\n\n render() {\n const selected = this.props.secondaryOptions[this.state.current_action]\n const SecondaryComponent = selected && selected.component\n return \n
\n o.value == this.state.current_action)}\n options={this.props.primaryOptions} onChange={(val) => this.onActionChanged(val)} />\n
\n {selected &&\n
\n this.onChange(vals)}/>\n
\n }\n {!selected &&\n
\n \n
\n }\n
this.onApply()}>{gettext(\"Apply\")} \n
\n }\n}\n\n\nexport const IndexView = observer(\n ({store}) => {\n\n const allCountryOptions = Object.entries(store.allCountries).map(([id, country]) => ({value: country.id, label: country.name}))\n const countryFilterOptions = Object.entries(store.countries).map(([id, country]) => ({value: country.id, label: country.name}))\n const organizationFilterOptions = Object.entries(store.organizations).map(([id, org]) => ({value: org.id, label: org.name}))\n const sectorFilterOptions = store.sectors.map(x => ({value: x.id, label: x.name}))\n const programFilterOptions = Object.entries(store.programFilterPrograms).map(([id, program]) => ({value: program.id, label: program.name}))\n const userFilterOptions = Object.entries(store.users).map(([id, user]) => ({value: user.id, label: user.name}))\n const bulkProgramStatusOptions = [\n {value: 'Funded', label: gettext('Funded')},\n {value: 'Completed', label: gettext('Completed')},\n ]\n\n const bulk_actions = {\n primary_options: [\n {label: gettext('Set program status'), value: 'set_program_status'},\n ],\n secondary_options: {\n set_program_status: {\n component: (props) => ,\n onApply: (option) => store.bulkUpdateProgramStatus(option.value)\n },\n }\n }\n\n const organizationColumn = (data) => {\n if (data.organizations) {\n return (\n \n \n { data.onlyOrganizationId ? store.organizations[data.onlyOrganizationId].name : `${data.organizations} organizations` }\n \n )\n }\n return \"---\"\n }\n\n return \n
\n \n
\n
\n
\n
\n
\n
\n
\n store.applyFilters()}>{gettext(\"Apply\")} \n store.clearFilters()}>{gettext(\"Reset\")} \n
\n
\n \n
\n
\n
\n \n \n
\n
{store.program_count ? `${store.program_count} ${gettext(\"programs\")}`:`---`}
\n
\n {store.total_pages &&\n
store.changePage(page)} />\n }\n \n
\n
\n
\n }\n)\n","import React from 'react'\nimport { observer } from \"mobx-react\"\n\n@observer\nexport default class ProgramEditor extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n active_page: 'profile'\n }\n }\n\n updateActivePage(new_page) {\n if(!this.props.new) {\n this.setState({active_page: new_page})\n }\n }\n\n render() {\n const {ProfileSection, HistorySection} = this.props\n\n const profile_active_class = (this.state.active_page == 'profile')?'active':''\n const history_active_class = (this.state.active_page == 'status_and_history')?'active':''\n const new_class = (this.props.new)?'disabled':''\n\n return (\n \n
\n
\n {this.state.active_page == 'profile' &&\n
\n }\n\n {this.state.active_page == 'status_and_history' &&\n
\n }\n
\n
\n )\n }\n}\n","import React from 'react'\n\nclass Expander extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n folded: false,\n }\n }\n\n toggleFolded() {\n this.setState({\n folded: !this.state.folded\n })\n }\n\n render() {\n const {className, ...props} = this.props\n const icon = (this.state.folded)?\"fa-chevron-right\":\"fa-chevron-left\"\n return \n {!this.state.folded &&\n
{this.props.children} \n }\n\n
this.toggleFolded()}>\n \n
\n
\n }\n}\n\nexport default Expander\n","import { observable, computed, action, runInAction } from \"mobx\";\n\n\nexport class ProgramStore {\n\n //filter options\n @observable countries = {}\n @observable allCountries = {}\n @observable organizations = {}\n @observable users = {}\n @observable sectors = []\n\n @observable filters = {\n countries: [],\n organizations: [],\n sectors: [],\n programStatus: null,\n programs: [],\n users: []\n }\n\n @observable programFilterPrograms = []\n @observable programs = []\n @observable program_count = 0\n @observable new_program = null\n @observable fetching_main_listing = false\n @observable current_page = 0\n @observable total_pages = null\n @observable bulk_targets = new Map()\n @observable bulk_targets_all = false\n\n @observable editing_target = null\n @observable editing_errors = {}\n @observable fetching_editing_history = true\n @observable editing_target_history = null\n @observable saving = false\n\n @observable bulk_targets = new Map()\n @observable applying_bulk_updates = false\n @observable bulk_targets_all = false\n\n constructor(\n api,\n initialData,\n ) {\n this.api = api\n Object.assign(this, initialData)\n this.fetchPrograms()\n }\n\n marshalFilters(filters) {\n return Object.entries(filters).reduce((xs, [filterKey, filterValue]) => {\n if (Array.isArray(filterValue)) {\n xs[filterKey] = filterValue.map(x => x.value)\n } else if (filterValue) {\n xs[filterKey] = filterValue.value\n }\n return xs\n }, {})\n }\n\n @action\n fetchPrograms() {\n this.fetching_main_listing = true\n this.api.fetchPrograms(this.current_page + 1, this.marshalFilters(this.filters)).then(results => {\n runInAction(() => {\n this.fetching_main_listing = false\n this.programs = results.results\n this.program_count = results.total_results\n this.total_pages = results.total_pages\n this.next_page =results.next_page\n this.previous_page = results.previous_page\n })\n })\n this.api.fetchProgramsForFilter(this.marshalFilters(this.filters)).then(response => {\n runInAction(() => {\n this.programFilterPrograms = response.data\n })\n })\n\n }\n\n @action\n applyFilters() {\n this.current_page = 0\n this.fetchPrograms()\n }\n\n @action\n changePage(page) {\n if (page.selected == this.current_page) {\n return\n }\n this.current_page = page.selected\n this.bulk_targets = new Map()\n this.bulk_targets_all = false;\n this.fetchPrograms()\n }\n\n @action\n changeFilter(filterKey, value) {\n this.filters = Object.assign(this.filters, {[filterKey]: value})\n }\n\n @action\n clearFilters() {\n let clearFilters = {\n countries: [],\n organizations: [],\n sectors: [],\n programStatus: null,\n programs: [],\n users: []\n }\n this.filters = Object.assign(this.filters, clearFilters);\n }\n\n @action\n toggleEditingTarget(id) {\n if(this.editing_target == 'new') {\n this.programs.shift()\n this.editing_errors = {}\n }\n\n if(this.editing_target == id) {\n this.editing_target = false\n this.editing_errors = {}\n } else {\n this.editing_target = id\n this.fetching_editing_history = true\n this.api.fetchProgramHistory(id).then(resp => {\n runInAction(() => {\n this.fetching_editing_history = false\n this.editing_history = resp.data\n })\n })\n }\n }\n\n updateLocalPrograms(updated) {\n this.programs = this.programs.reduce((acc, current) => {\n if (current.id == updated.id) {\n acc.push(updated)\n } else {\n acc.push(current)\n }\n return acc\n }, [])\n }\n\n onSaveSuccessHandler() {\n PNotify.success({text: gettext(\"Successfully Saved\"), delay: 5000})\n }\n\n onSaveErrorHandler() {\n PNotify.error({text: gettext(\"Saving Failed\"), delay: 5000})\n }\n\n @action\n createProgram() {\n if(this.editing_target == 'new') {\n this.programs.shift()\n }\n\n let new_program_data = {\n id: \"new\",\n name: \"\",\n gaitid: \"\",\n fundcode: \"\",\n funding_status: \"\",\n description: \"\",\n country: [],\n sector: [],\n }\n this.programs.unshift(new_program_data)\n this.editing_target = 'new'\n }\n\n @action\n saveNewProgram(program_data) {\n program_data.id = null\n this.saving = true\n this.api.createProgram(program_data).then(response => {\n runInAction(()=> {\n this.saving = false\n this.editing_target = false\n this.programs.shift()\n this.programs.unshift(response.data)\n })\n }).catch(error => {\n runInAction(()=> {\n let errors = error.response.data\n this.saving = false\n this.editing_errors = errors\n })\n })\n }\n\n @action updateProgram(id, program_data) {\n this.saving = true\n this.api.updateProgram(id, program_data).then(response => {\n runInAction(() => {\n this.saving = false\n this.editing_target = false\n this.updateLocalPrograms(response.data)\n this.onSaveSuccessHandler()\n })\n }).catch((errors) => {\n runInAction(() => {\n this.saving = false\n this.editing_errors = errors.response.data\n this.onSaveErrorHandler()\n })\n })\n }\n\n @action\n toggleBulkTarget(target_id) {\n this.bulk_targets.set(target_id, !this.bulk_targets.get(target_id))\n }\n\n @action\n toggleBulkTargetsAll() {\n this.bulk_targets_all = !this.bulk_targets_all\n this.bulk_targets = new Map(this.programs.map(program => [program.id, this.bulk_targets_all]))\n }\n\n postBulkUpdateLocalPrograms(updatedPrograms) {\n let updatedProgramsById = new Map(updatedPrograms.map(program => [program.id, program]))\n this.programs = this.programs.reduce((acc, current) => {\n let updated = updatedProgramsById.get(current.id)\n if (updated) {\n acc.push(Object.assign(current, updated))\n } else {\n acc.push(current)\n }\n return acc\n }, [])\n }\n\n @action\n bulkUpdateProgramStatus(new_status) {\n let ids = Array.from(this.bulk_targets.entries()).filter(([id, targeted]) => targeted).map(([id, targeted]) => id)\n if (ids.length && new_status) {\n this.applying_bulk_updates = true\n this.api.updateProgramFundingStatusBulk(ids, new_status).then(response => {\n let updatedPrograms = response.data\n runInAction(() => {\n this.postBulkUpdateLocalPrograms(updatedPrograms)\n this.applying_bulk_updates = false\n this.onSaveSuccessHandler()\n })\n }).catch(error => {\n runInAction(() => {\n this.applying_bulk_updates = false\n this.onSaveErrorHandler()\n })\n })\n }\n }\n\n}\n"],"mappings":"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AAKA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AADA;AAAA;AADA;AAMA;AAAA;AAWA;;;;AAhDA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACLA;AACA;AACA;;;;;AACA;AAAA;AACA;AADA;AACA;AAAA;AACA;AACA;AADA;AAFA;AAKA;AACA;;;AACA;AACA;AACA;AADA;AAGA;;;AAEA;AAAA;AACA;AADA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAKA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAGA;;;;AA1BA;AACA;AA4BA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/BA;AAGA;AAAA;AAAA;AAEA;AAoCA;AAGA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AADA;AACA;AAAA;AACA;AACA;AACA;AACA;AA9CA;AAAA;AAAA;AAgDA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAxDA;AAAA;AAAA;AA2DA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AA7EA;AAAA;AAAA;AAiFA;AACA;AACA;AAnFA;AAAA;AAAA;AAuFA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AA9FA;AAAA;AAAA;AAkGA;AACA;AAnGA;AAAA;AAAA;AAuGA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAQA;AACA;AAhHA;AAAA;AAAA;AAmHA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAtIA;AAAA;AAAA;AAyIA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AAjJA;AAAA;AAAA;AAoJA;AAAA;AAAA;AAAA;AACA;AArJA;AAAA;AAAA;AAwJA;AAAA;AAAA;AAAA;AACA;AAzJA;AAAA;AAAA;AA6JA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AARA;AAUA;AACA;AACA;AA7KA;AAAA;AAAA;AAgLA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAjMA;AAAA;AAAA;AAmMA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AAnNA;AAAA;AAAA;AAuNA;AACA;AAxNA;AAAA;AAAA;AA2NA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AA9NA;AAAA;AAAA;AAiOA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AA3OA;AAAA;AAAA;AA8OA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AAhQA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA;AACA;AACA;AACA;AACA;AACA;AANA;AATA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;;A","sourceRoot":""}
\ No newline at end of file
diff --git a/build/dev-dist/tola_management_user-2e62a5cc5ee41288dcc0.js.map b/build/dev-dist/tola_management_user-2e62a5cc5ee41288dcc0.js.map
deleted file mode 100644
index 7a9039b8..00000000
--- a/build/dev-dist/tola_management_user-2e62a5cc5ee41288dcc0.js.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"file":"tola_management_user-2e62a5cc5ee41288dcc0.js","sources":["webpack:///./js/pages/tola_management_pages/user/components/edit_user_programs.js","webpack:///./js/components/virtualized-react-select.js","webpack:///./js/pages/tola_management_pages/user/components/edit_user_profile.js","webpack:///./js/pages/tola_management_pages/user/index.js","webpack:///./js/components/loading-spinner.js","webpack:///./js/pages/tola_management_pages/user/components/edit_user_history.js","webpack:///./js/components/expander.js","webpack:///./js/pages/tola_management_pages/user/api.js","webpack:///./js/components/pagination.js","webpack:///./js/components/management-table.js","webpack:///./js/api.js","webpack:///./js/components/checkboxed-multi-select.js","webpack:///./js/pages/tola_management_pages/user/views.js","webpack:///./js/pages/tola_management_pages/user/models.js","webpack:///./js/pages/tola_management_pages/user/components/user_editor.js","webpack:///./js/components/folding-sidebar.js"],"sourcesContent":["import React from 'react'\nimport { observer } from \"mobx-react\"\nimport {AutoSizer, Table, Column, CellMeasurer, CellMeasurerCache} from 'react-virtualized'\nimport Select from 'components/virtualized-react-select'\n\n//we need a pretty peculiar structure to accommodate the virtualized table\nconst create_country_objects = (countries, store) => Object.entries(countries)\n .reduce((countries, [id, country]) => ({\n ...countries,\n [id]: {\n ...country,\n type: 'country',\n options: [{label: '', value: 'none'}, ...store.country_role_choices],\n admin_access: store.is_superuser,\n programs: new Set(country.programs)\n }\n }),{})\n\nconst create_program_objects = (programs, store) => Object.entries(programs)\n .reduce((programs, [id, program]) => ({\n ...programs,\n [id]: {\n ...program,\n type: 'program',\n options: store.program_role_choices,\n }\n }),{})\n\n//we need to flatten the country -> program heirarchy to support the virtualized table\nconst flattened_listing = (countries, programs) => countries.flatMap(country =>\n [\n country,\n ...Array.from(country.programs)\n .filter(program_id => programs[program_id])\n .map(program_id => ({...programs[program_id], id: `${country.id}_${program_id}`, country_id: country.id}))\n ]\n )\n\nconst apply_program_filter = (programs, countries, filter_string) => {\n if(!filter_string) {\n return {\n programs,\n countries\n }\n }\n const filtered_programs = Object.entries(programs).filter(([_, program]) => program.name.toLowerCase().includes(filter_string.toLowerCase())).map(([_, p]) => p)\n const filtered_countries = Object.entries(countries).filter(([_, country]) => filtered_programs.some(program => country.programs.has(program.id))).map(([_, c]) => c)\n\n return {\n countries: filtered_countries.reduce((countries, country) => ({...countries, [country.id]: country}), {}),\n programs: filtered_programs.reduce((programs, program) => ({...programs, [program.id]: program}), {}),\n }\n}\n\nconst apply_country_filter = (countries, filtered) => {\n if(filtered.length > 0) {\n return filtered.filter(option => countries[option.value])\n .map(option => countries[option.value])\n .reduce((countries, country) => ({...countries, [country.id]: country}), {})\n } else {\n return countries\n }\n}\n\nconst create_user_access = (user_access) => ({\n countries: Object.entries(user_access.countries).reduce((countries, [id, country]) => ({...countries, [id]: {...country, has_access: true}}), {}),\n programs: user_access.programs.reduce((programs, program) => ({...programs, [`${program.country}_${program.program}`]: {...program, has_access: true}}), {})\n})\n\nconst country_has_all_access = (country, visible_programs, user_program_access) =>\n Array.from(country.programs)\n .filter(program_id => !!visible_programs[program_id])\n .every(program_id =>\n user_program_access.programs[`${country.id}_${program_id}`]\n && user_program_access.programs[`${country.id}_${program_id}`].has_access\n )\n\n@observer\nexport default class EditUserPrograms extends React.Component {\n constructor(props) {\n super(props)\n const {store} = props\n\n const countries = create_country_objects(store.countries, store)\n const programs = create_program_objects(store.programs, store)\n\n this.state = {\n program_filter: '',\n country_filter: [],\n country_selections: Object.entries(store.countries).map(([_, country]) => ({value: country.id, label: country.name})),\n countries,\n programs,\n filtered_countries: countries,\n filtered_programs: programs,\n ordered_country_ids: store.ordered_country_ids,\n flattened_programs: flattened_listing(store.ordered_country_ids.filter(id => id in countries).map(id => countries[id]), programs),\n original_user_program_access: create_user_access(store.editing_target_data.access),\n user_program_access: create_user_access(store.editing_target_data.access)\n }\n }\n\n componentWillReceiveProps(next_props) {\n const {store} = next_props\n const countries_obj = create_country_objects(store.countries, store)\n const programs_obj = create_program_objects(store.programs, store)\n\n const filtered_countries = apply_country_filter(\n countries_obj,\n this.state.country_filter\n )\n\n const {countries, programs}= apply_program_filter(\n programs_obj,\n filtered_countries,\n this.state.program_filter\n )\n\n this.setState({\n countries: countries_obj,\n programs: programs_obj,\n country_selections: Object.entries(store.countries).map(([_, country]) => ({value: country.id, label: country.name})),\n filtered_countries: countries,\n filtered_programs: programs,\n ordered_country_ids: store.ordered_country_ids,\n flattened_programs: flattened_listing(store.ordered_country_ids.filter(id => id in countries).map(id => countries[id]), programs),\n original_user_program_access: create_user_access(store.editing_target_data.access),\n user_program_access: create_user_access(store.editing_target_data.access)\n })\n }\n\n saveForm() {\n //marshal the data back into the format we received it\n //filtering out all !has_access\n const access = this.state.user_program_access\n this.props.onSave({\n countries: Object.entries(access.countries)\n .filter(([_, country]) => this.props.store.is_superuser)\n .filter(([_, country]) => country.has_access)\n .reduce((countries, [id, country]) => ({...countries, [id]: country}), {}),\n programs: Object.entries(access.programs)\n .filter(([_, program]) => program.has_access)\n .map(([_, program]) => program)\n })\n }\n\n resetForm() {\n this.setState({\n user_program_access: {\n countries: {...this.state.original_user_program_access.countries},\n programs: {...this.state.original_user_program_access.programs}\n }\n })\n\n }\n\n toggleProgramAccess(program_key) {\n const current_program_access = this.state.user_program_access.programs\n const updated_program_access = (() => {\n if(current_program_access[program_key]) {\n return {...current_program_access[program_key], has_access: !current_program_access[program_key].has_access}\n } else {\n //TODO: want to find a more resilient way to handle a compound key\n const [country, program] = program_key.split('_')\n return {country, program, role: 'low', has_access: true}\n }\n })()\n\n this.setState({\n user_program_access: {\n ...this.state.user_program_access,\n programs: {\n ...current_program_access,\n [program_key]: updated_program_access\n }\n }\n })\n }\n\n toggleAllProgramsForCountry(country_id) {\n const country = this.state.countries[country_id]\n\n const new_program_access = (() => {\n const country_has_all_checked = country_has_all_access(\n country,\n this.state.filtered_programs,\n this.state.user_program_access\n )\n\n if(country_has_all_checked) {\n //toggle all off\n return Array.from(country.programs).filter(program_id => {\n return !!this.state.filtered_programs[program_id]\n }).reduce((programs, program_id) => {\n const program_key = `${country.id}_${program_id}`\n const program = this.state.user_program_access.programs[program_key]\n if(program) {\n return {...programs, [program_key]: {...program, has_access: false}}\n } else {\n return programs\n }\n }, {})\n } else {\n //toggle all on\n return Array.from(country.programs).filter(program_id => {\n return !!this.state.filtered_programs[program_id]\n }).reduce((programs, program_id) => {\n const program_key = `${country.id}_${program_id}`\n const program = this.state.user_program_access.programs[program_key]\n if(program) {\n return {...programs, [program_key]: {...program, has_access: true}}\n } else {\n return {...programs, [program_key]: {program: program_id, country: country.id, role: 'low', has_access: true}}\n }\n }, {})\n }\n })()\n this.setState({\n user_program_access: {\n ...this.state.user_program_access,\n programs: {...this.state.user_program_access.programs, ...new_program_access}\n }\n })\n }\n\n changeCountryRole(country_id, new_val) {\n const country = {...this.state.user_program_access.countries[country_id]}\n const new_country_access = (() => {\n if(new_val != 'none') {\n return {...country, role: new_val, has_access: true}\n } else {\n return {...country, role: new_val, has_access: false}\n }\n })()\n\n this.setState({\n user_program_access: {\n ...this.state.user_program_access,\n countries: {\n ...this.state.user_program_access.countries,\n [country_id]: new_country_access\n }\n },\n })\n }\n\n changeProgramRole(program_key, new_val) {\n const [country_id, program_id] = program_key.split('_')\n const access = this.state.user_program_access\n\n\n const new_program_access = (() => {\n if(access[country_id] && access[country_id].has_access && new_val == 'low') {\n return {\n program: program_id,\n country: country_id,\n role: new_val,\n has_access: false\n }\n } else {\n return {\n program: program_id,\n country: country_id,\n role: new_val,\n has_access: true\n }\n }\n })()\n\n this.setState({\n user_program_access: {\n ...this.state.user_program_access,\n programs: {\n ...this.state.user_program_access.programs,\n [program_key]: new_program_access\n }\n }\n })\n }\n\n clearFilter() {\n const val = ''\n const filtered_countries = apply_country_filter(this.state.countries, this.state.country_filter)\n const {countries, programs} = apply_program_filter(\n this.state.programs,\n filtered_countries,\n val\n )\n\n this.setState({\n program_filter: val,\n filtered_programs: programs,\n filtered_countries: countries,\n flattened_programs: flattened_listing(this.state.ordered_country_ids.filter(id => id in countries).map(id => countries[id]), programs),\n })\n }\n\n updateProgramFilter(val) {\n const filtered_countries = apply_country_filter(this.state.countries, this.state.country_filter)\n const {countries, programs} = apply_program_filter(\n this.state.programs,\n filtered_countries,\n val\n )\n\n this.setState({\n program_filter: val,\n filtered_programs: programs,\n filtered_countries: countries,\n flattened_programs: flattened_listing(this.state.ordered_country_ids.filter(id => id in countries).map(id => countries[id]), programs),\n })\n }\n\n changeCountryFilter(e) {\n const filtered_countries = apply_country_filter(this.state.countries, e)\n const {countries, programs} = apply_program_filter(\n this.state.programs,\n filtered_countries,\n this.state.program_filter\n )\n\n this.setState({\n country_filter: e,\n filtered_countries: countries,\n flattened_programs: flattened_listing(this.state.ordered_country_ids.filter(id => id in countries).map(id => countries[id]), this.state.filtered_programs),\n })\n }\n\n render() {\n const {user, onSave} = this.props\n\n const is_checked = (data) => {\n const access = this.state.user_program_access\n if(data.type == 'country') {\n return (access.countries[data.id] && access.countries[data.id].has_access) || false\n } else {\n if(this.state.user_program_access.countries[data.country_id] && this.state.user_program_access.countries[data.country_id].has_access) {\n return true\n }\n return (access.programs[data.id] && access.programs[data.id].has_access) || false\n }\n }\n\n const is_check_disabled = (data) => {\n if(data.type == 'country') {\n return !(this.state.countries[data.id].programs.size > 0)\n || !(\n this.props.store.access.countries[data.id]\n && this.props.store.access.countries[data.id].role == 'basic_admin'\n )\n || (\n this.state.user_program_access.countries[data.id]\n && this.state.user_program_access.countries[data.id].has_access\n )\n\n } else {\n if(this.state.user_program_access.countries[data.country_id] && this.state.user_program_access.countries[data.country_id].has_access) {\n return true\n }\n return !this.props.store.access.countries[data.country_id] || this.props.store.access.countries[data.country_id].role != 'basic_admin'\n }\n }\n\n const is_role_disabled = (data) => {\n if(data.type == 'country') {\n return !this.props.store.is_superuser\n } else {\n return (\n !this.props.store.access.countries[data.country_id]\n || this.props.store.access.countries[data.country_id].role != 'basic_admin'\n || (\n !(\n this.state.user_program_access.programs[data.id]\n && this.state.user_program_access.programs[data.id].has_access\n ) && !(\n this.state.user_program_access.countries[data.country_id]\n && this.state.user_program_access.countries[data.country_id].has_access\n )\n )\n )\n }\n }\n\n const get_role = (data) => {\n if(data.type == 'country') {\n const country_access = this.state.user_program_access.countries\n if(!country_access[data.id]) {\n return 'none'\n } else {\n return country_access[data.id].role\n }\n } else {\n const program_access = this.state.user_program_access.programs\n if(!program_access[data.id]) {\n return this.props.store.program_role_choices[0].value\n } else {\n return program_access[data.id].role\n }\n }\n }\n\n return (\n \n
{user.name?user.name+': ':''}{gettext(\"Programs and Roles\")} \n\n
\n
\n this.changeCountryFilter(e)} />\n
\n
\n
\n
this.updateProgramFilter(e.target.value)} />\n
\n
\n
\n
\n\n
\n
\n {({height, width}) =>\n this.state.flattened_programs[index]}\n rowHeight={50}\n rowCount={this.state.flattened_programs.length}>\n\n ({\n checked: is_checked(rowData),\n disabled: is_check_disabled(rowData),\n id: rowData.id,\n type: rowData.type,\n action: (rowData.type == \"country\")?this.toggleAllProgramsForCountry.bind(this):this.toggleProgramAccess.bind(this)\n })}\n cellRenderer={({cellData}) => {\n if (cellData.type == 'country') {\n const country_has_all_checked = country_has_all_access(\n this.state.countries[cellData.id],\n this.state.filtered_programs,\n this.state.user_program_access\n )\n const button_label = (country_has_all_checked)?gettext('Deselect All'):gettext('Select All')\n if(cellData.disabled) {\n return null\n } else {\n return \n }\n } else {\n return cellData.action(cellData.id)} />
\n }\n }}/>\n\n ({bold: rowData.type == \"country\", name: rowData.name})}\n cellRenderer={({cellData}) => {\n if(cellData.bold) {\n return {cellData.name} \n } else {\n return {cellData.name} \n }\n }} />\n\n ({\n id: rowData.id,\n disabled: is_role_disabled(rowData),\n type: rowData.type,\n options: rowData.options,\n action: (rowData.type == \"country\")?this.changeCountryRole.bind(this):this.changeProgramRole.bind(this)\n })}\n cellRenderer={({cellData}) =>\n cellData.action(cellData.id, e.target.value)}>\n {cellData.options.map(option => {option.label} )}\n \n }/>\n\n
\n }\n \n
\n\n
\n this.saveForm()}>Save Changes \n this.resetForm()}>Reset \n
\n\n
\n )\n }\n}\n","import React from 'react'\nimport {List, AutoSizer, CellMeasurer, CellMeasurerCache} from 'react-virtualized'\nimport Select, {components} from 'react-select'\n\nexport class VirtualizedMenuList extends React.PureComponent {\n constructor(props) {\n super(props)\n this.cache = new CellMeasurerCache({\n fixedWidth: true,\n defaultHeight: 35,\n })\n this.filter_val = \"\"\n }\n\n render() {\n const {options, children, maxHeight, getValue, selectProps} = this.props\n const rowCount = children.length || 0\n\n //gotta be a way to improve this. it's ok after the first couple of\n //characters search, but it's slow prior to that\n if(selectProps.inputValue !== this.filter_val) {\n this.filter_val = selectProps.inputValue\n this.cache.clearAll()\n }\n\n return (\n \n
\n
\n {({width, height}) => {\n return No selections available
}\n rowRenderer={\n ({index, parent, key, style}) =>\n \n {children[index]}
\n \n }/>\n }}\n
\n
\n
\n )\n }\n}\n\nconst VirtualizedSelect = props => (\n \n)\n\nexport default VirtualizedSelect\n","import React from 'react'\nimport Select from 'react-select'\nimport { observer } from \"mobx-react\"\n\n@observer\nexport default class EditUserProfile extends React.Component {\n constructor(props) {\n super(props)\n const {userData} = props\n const organization_listing = (() => {\n if(props.new) {\n return props.organizations.filter(o => o.value != 1 || props.is_superuser)\n } else {\n return props.organizations\n }\n })()\n const selected_organization = organization_listing.find(o => o.value == userData.organization_id)\n this.state = {\n original_user_data: {...userData},\n managed_user_data: {...userData},\n selected_organization,\n organization_listing\n }\n }\n\n\n save(e) {\n e.preventDefault()\n this.props.onUpdate(this.state.managed_user_data)\n }\n\n saveNew(e) {\n e.preventDefault()\n this.props.onCreate(this.state.managed_user_data)\n }\n\n saveNewAndAddAnother(e) {\n e.preventDefault()\n this.props.onCreateAndAddAnother(this.state.managed_user_data)\n }\n\n updateFirstName(new_first_name) {\n this.setState({\n managed_user_data: {\n ...this.state.managed_user_data,\n first_name: new_first_name,\n }\n })\n }\n\n updateLastName(new_last_name) {\n this.setState({\n managed_user_data: {\n ...this.state.managed_user_data,\n last_name: new_last_name,\n }\n })\n }\n\n updateOrganization(new_option) {\n this.setState({\n managed_user_data: {\n ...this.state.managed_user_data,\n organization_id: new_option.value,\n },\n selected_organization: new_option\n })\n }\n\n updateTitle(new_title) {\n this.setState({\n managed_user_data: {\n ...this.state.managed_user_data,\n title: new_title,\n }\n })\n }\n\n updateEmail(new_email) {\n this.setState({\n managed_user_data: {\n ...this.state.managed_user_data,\n email: new_email,\n }\n })\n }\n\n updatePhone(new_phone) {\n this.setState({\n managed_user_data: {\n ...this.state.managed_user_data,\n phone: new_phone,\n }\n })\n }\n\n updateModeOfContact(new_mode_of_contact) {\n this.setState({\n managed_user_data: {\n ...this.state.managed_user_data,\n mode_of_contact: new_mode_of_contact,\n }\n })\n }\n\n resetForm() {\n const selected_organization = this.state.organization_listing.find(o => o.value == this.state.original_user_data.organization_id)\n this.setState({\n managed_user_data: this.state.original_user_data,\n selected_organization\n })\n }\n\n render() {\n const ud = this.state.managed_user_data\n const e = this.props.errors\n const disabled = this.props.disabled\n const error_classes = {\n first_name: (e.first_name)?'is-invalid':'',\n last_name: (e.last_name)?'is-invalid':'',\n email: (e.email)?'is-invalid':'',\n organization: (e.organization_id)?'is-invalid':''\n }\n return (\n \n
{ud.name? ud.name+': ':''}Profile \n
\n \n
{gettext(\"Preferred First Name\")}* \n
this.updateFirstName(e.target.value) }\n id=\"user-first-name-input\"\n required />\n {e.first_name &&\n
\n {e.first_name}\n
\n }\n
\n \n
{gettext(\"Preferred Last Name\")}* \n
this.updateLastName(e.target.value) }\n id=\"user-last-name-input\"\n required />\n {e.last_name &&\n
\n {e.last_name}\n
\n }\n
\n \n
{gettext(\"Organization\")}* \n
this.updateOrganization(e)}\n placeholder=\"None Selected\"\n id=\"user-organization-input\" />\n {e.organization_id &&\n \n {e.organization_id}\n
\n }\n \n \n {gettext(\"Title\")} \n this.updateTitle(e.target.value)}\n className=\"form-control\"\n id=\"user-title-input\" />\n
\n \n
{gettext(\"Email\")}* \n
this.updateEmail(e.target.value)}\n id=\"user-email-input\" />\n {e.email &&\n
\n {e.email}\n
\n }\n
\n \n {gettext(\"Phone\")} \n this.updatePhone(e.target.value)}\n className=\"form-control\"\n id=\"user-phone-input\" />\n
\n \n {gettext(\"Preferred Mode of Contact\")} \n this.updateModeOfContact(e.target.value)}\n className=\"form-control\"\n id=\"user-mode-of-contact-input\" />\n
\n {this.props.new && !disabled &&\n \n this.saveNew(e)}>{gettext(\"Save changes\")} \n this.saveNewAndAddAnother(e)}>{gettext(\"Save And Add Another\")} \n this.resetForm()}>{gettext(\"Reset\")} \n
\n }\n {!this.props.new && !disabled &&\n \n this.save(e)}>{gettext(\"Save changes\")} \n this.resetForm()}>{gettext(\"Reset\")} \n
\n }\n \n
\n )\n }\n}\n","import React from 'react';\nimport ReactDOM from 'react-dom';\nimport {UserStore} from './models';\nimport {IndexView} from './views';\n\n/*\n * Model/Store setup\n */\nconst store = new UserStore(jsContext);\n\nReactDOM.render(\n ,\n document.querySelector('#app_root')\n);\n","\nimport React from 'react'\n\nconst LoadingSpinner = ({children, isLoading, className, ...props}) => {\n const loading = (isLoading)?'loading':''\n return \n}\n\nexport default LoadingSpinner\n","import React from 'react'\nimport { observer } from \"mobx-react\"\nimport Select from 'react-select'\nimport {AutoSizer, Table, Column, CellMeasurer, CellMeasurerCache} from 'react-virtualized'\nimport Expander from 'components/expander'\n\nconst status_options = [\n {value: true, label: gettext('Active')},\n {value: false, label: gettext('Inactive')}\n]\n\nconst ChangesetEntry = ({name, type, data}) => {\n return {name} : {(data != undefined && data != null)?data.toString():'N/A'}
\n}\n\nconst ProgramChangesetEntry = ({data, timeframe}) => {\n return \n {Object.entries(data.countries).length > 0 &&\n
\n
Countries \n {Object.entries(data.countries).map(([id, country]) =>\n
\n
{gettext(\"Country\")} : {country[timeframe].country}
\n
{gettext(\"Role\")} : {country[timeframe].role}
\n
\n )}\n
\n }\n {Object.entries(data.programs).length > 0 &&\n
\n
Programs \n {Object.entries(data.programs).map(([id, program]) =>\n
\n
{gettext(\"Program\")} : {program[timeframe].program}
\n
{gettext(\"Country\")} : {program[timeframe].country}
\n
{gettext(\"Role\")} : {program[timeframe].role}
\n
\n )}\n
\n }\n
\n}\n\nexport class EditUserHistory extends React.Component {\n\n constructor(props) {\n super(props)\n this.state = {\n original_user_data: {user: {is_active: props.userData.user.is_active}},\n user_data: {user: {is_active: props.userData.user.is_active}}\n }\n }\n\n onChange(new_value) {\n this.setState({\n user_data: {\n user: {is_active: new_value.value}\n }\n })\n }\n\n onResendRegistrationEmail() {\n this.props.onResendRegistrationEmail()\n }\n\n onReset() {\n this.setState({\n user_data: this.state.original_user_data\n })\n }\n\n render() {\n const selected = status_options.find(option => option.value == this.state.user_data.user.is_active)\n const {history} = this.props\n return \n
{this.state.user_data.name?this.state.user_data.name+': ':''}{gettext(\"Status and History\")} \n
\n this.onChange(new_value)} />\n
\n
\n this.onResendRegistrationEmail()}>{gettext(\"Resend Registration Email\")} \n
\n {!this.props.disabled &&\n
\n
\n this.props.onSave(this.state.user_data)}>{gettext(\"Save Changes\")} \n this.onReset()}>{gettext(\"Reset\")} \n
\n
\n }\n
\n \n \n {gettext(\"Date\")} \n {gettext(\"Admin\")} \n {gettext(\"Change Type\")} \n {gettext(\"Previous Entry\")} \n {gettext(\"New Entry\")} \n \n \n \n {history.map(entry => {\n if(entry.change_type == 'user_programs_updated') {\n return \n {entry.date} \n {entry.admin_user} \n {entry.change_type} \n \n \n \n \n \n \n \n \n \n \n \n } else {\n\n return \n {entry.date} \n {entry.admin_user} \n {entry.change_type} \n \n \n {entry.diff_list.map(changeset => {\n return \n })}\n \n \n \n \n {entry.diff_list.map(changeset => {\n return \n })}\n \n \n \n }\n })}\n \n
\n
\n }\n}\n\nexport default EditUserHistory\n","import React from 'react'\n\nclass Expander extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n expanded: false,\n overflowing: false,\n }\n this.ref = React.createRef()\n }\n\n componentDidMount() {\n if(this.ref.current.scrollHeight > this.ref.current.clientHeight) {\n this.setState({overflowing: true})\n }\n }\n\n toggleExpanded(e) {\n e.preventDefault()\n this.setState({\n expanded: !this.state.expanded\n })\n }\n\n render() {\n return \n
\n {this.props.children}\n
\n {this.state.overflowing &&\n
\n }\n
\n }\n}\n\nexport default Expander\n","import {api} from '../../../api';\n\nexport const fetchUsersWithFilter = (page, filters) => api.get('/tola_management/user/', {params: {page: page, ...filters}}).then(response => {\n let data = response.data\n\n let total_results_count = data.count\n let current_results_count = data.results.length\n let total_pages = data.page_count\n\n return {\n users: data.results,\n total_pages: total_pages,\n total_users: total_results_count,\n next_page: data.next,\n prev_page: data.previous\n }\n})\n\nexport const fetchUser = (user_id) => api.get(`/tola_management/user/${user_id}/`).then(response => response.data)\n\nexport const saveUserProfile = (user_id, data) => api.put(`/tola_management/user/${user_id}/`, data).then((response) => {\n return response.data\n})\n\nexport const updateUserIsActive = (user_id, data) => api.put(`/tola_management/user/${user_id}/is_active/`, data).then(response => response.data)\n\nexport const fetchUserProgramAccess = (user_id) => api.get(`/tola_management/user/${user_id}/program_access/`).then(response => response.data)\n\nexport const saveUserPrograms = (user_id, data) => api.put(`/tola_management/user/${user_id}/program_access/`, data).then(response => {\n\n})\n\nexport const fetchUserHistory = (user_id) => api.get(`/tola_management/user/${user_id}/history/`).then(response => response.data)\n\nexport const createUser = (new_user_data) => api.post(`/tola_management/user/`, new_user_data).then(response => {\n return response.data\n})\n\nexport const resendRegistrationEmail = (user_id) => api.post(`/tola_management/user/${user_id}/resend_registration_email/`, {}).then(response => response.data)\n\nexport const bulkUpdateUserStatus = (user_ids, new_status) => api.post(`/tola_management/user/bulk_update_status/`, {user_ids, new_status}).then(response => response.data)\nexport const bulkAddPrograms = (user_ids, added_programs) => api.post(`/tola_management/user/bulk_add_programs/`, {user_ids, added_programs}).then(response => response.data)\nexport const bulkRemovePrograms = (user_ids, removed_programs) => api.post(`/tola_management/user/bulk_remove_programs/`, {user_ids, removed_programs}).then(response => response.data)\n\nexport const fetchUserAggregates = (user_id) => api.get(`/tola_management/user/${user_id}/aggregate_data/`).then(response => response.data)\n\nexport default {\n fetchUsersWithFilter,\n fetchUser,\n saveUserProfile,\n fetchUserProgramAccess,\n saveUserPrograms,\n fetchUserHistory,\n createUser,\n resendRegistrationEmail,\n bulkUpdateUserStatus,\n bulkAddPrograms,\n bulkRemovePrograms,\n fetchUserAggregates,\n updateUserIsActive\n}\n","import React from 'react'\nimport ReactPaginate from 'react-paginate'\nimport { observer } from \"mobx-react\"\n\n/***\n Props:\n\n - pageCount: total number of pages\n - initialPage: which page should be highlighted as active initially\n - onPageChange: a function to receive the newly selected page\n*/\nconst Pagination = (props) => {\n return \n}\n\nexport default Pagination\n","import { observer } from \"mobx-react\"\nimport React from 'react';\nimport classNames from 'classnames';\n\n// TODO: \"size\" is no longer used\nconst ColumnComponent = ({className, size, ...props}) => {props.children} \n\n// TODO: this is redundant with ColumnComponent\nconst HeaderColumnComponent = ({className, size, ...props}) => {props.children} \n\nconst InnerRowComponent = ({className, ...props}) => {props.children} \n\n// TODO: this is redundant with InnerRowComponent\nconst HeaderRowComponent = ({className, ...props}) => {props.children} \n\n/***\n A wrapper for the rendering of the given row renderer, it takes and expando\n renderer used to render expanded content\n\n Props:\n - expanded: whether the expando content is shown or not\n - Expando: The content to render when the expando is shown\n*/\nconst RowComponent = observer(({className, expanded, Expando, ...props}) => {\n if(Expando) {\n const ObservedExpando = observer(Expando)\n return \n {props.children} \n {expanded && }\n \n } else {\n return \n {props.children} \n \n }\n})\nconst ExpandoWrapper = ({className, ...props}) => {props.children} \n\nconst RowList = observer(({data, Row, keyField, ...props}) => {\n const ObservedRow = observer(Row)\n return data.map(row_data => )\n})\n\n/*\n Props:\n\n - HeaderRow: a function to render the header row. it receives a component\n prop to render the header column and row\n\n - Row: a function used to render each row. it receives a component prop to\n render the row (see RowComponent), it receives the relevant data for that\n row as a prop: data\n\n - data: the dataset used to render the table, it must be an array\n\n - keyField: field to use for key on rows and expando checking\n\n */\nconst ManagementTable = observer(({HeaderRow, className, ...props}) => {\n const ObservedHeaderRow = observer(HeaderRow)\n return \n})\nexport default ManagementTable\n","import axios from 'axios';\n\nexport const api = axios.create({\n withCredentials: true,\n baseURL: '/api/',\n headers: {\n \"X-CSRFToken\": document.cookie.replace(/(?:(?:^|.*;\\s*)csrftoken\\s*\\=\\s*([^;]*).*$)|^.*$/, \"$1\")\n }\n});\n","import React from 'react'\nimport Select, {components} from 'react-select'\nimport {VirtualizedMenuList as MenuList} from './virtualized-react-select'\nimport {observer} from 'mobx-react'\n\nconst Option = props => {\n return (components.Option &&\n \n {\n //we can let the outer component manage state\n }}\n />\n \n {props.data.label}\n \n )\n}\n\nconst CheckboxedMultiSelect = observer(props => (\n \n))\n\nexport default CheckboxedMultiSelect\n","import React from 'react'\nimport { observer } from \"mobx-react\"\nimport Select from 'react-select'\nimport CheckboxedMultiSelect from 'components/checkboxed-multi-select'\nimport ManagementTable from 'components/management-table'\nimport UserEditor from './components/user_editor'\nimport EditUserProfile from './components/edit_user_profile'\nimport EditUserPrograms from './components/edit_user_programs'\nimport EditUserHistory from './components/edit_user_history'\nimport Pagination from 'components/pagination'\nimport LoadingSpinner from 'components/loading-spinner'\nimport FoldingSidebar from 'components/folding-sidebar'\n\nconst selection_placeholder = gettext(\"None Selected\")\nconst UserFilter = observer(({store, selections}) => {\n return \n {gettext(\"Users\")} \n store.changeUserFilter(e)}\n placeholder={selection_placeholder}\n id=\"users_filter\" />\n
\n})\n\nconst CountryFilter = observer(({store, selections}) => {\n return \n {gettext(\"Countries Permitted\")} \n store.changeCountryFilter(e)}\n placeholder={selection_placeholder}\n id=\"countries_permitted_filter\" />\n
\n})\n\nconst BaseCountryFilter = observer(({store, selections}) => {\n return \n {gettext(\"Base Country\")} \n store.changeBaseCountryFilter(e)}\n placeholder={selection_placeholder}\n id=\"base_country_filter\" />\n
\n})\n\nconst ProgramFilter = observer(({store, selections}) => {\n return \n {gettext(\"Programs\")} \n store.changeProgramFilter(e)}\n placeholder={selection_placeholder}\n id=\"programs_filter\" />\n
\n})\n\nclass SetUserStatusBulkAction extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n value: []\n }\n }\n\n onChange(new_val) {\n this.setState({\n value: new_val\n })\n }\n\n onApply() {\n this.props.onApply(this.state.value)\n }\n\n render() {\n return this.onChange(val)} />\n }\n}\n\nclass UpdateProgramsBulkAction extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n values: []\n }\n }\n\n onChange(new_vals) {\n this.setState({\n values: new_vals\n })\n }\n\n render() {\n return this.onChange(val)} />\n }\n}\n\nclass BulkActions extends React.Component {\n constructor(props) {\n super(props)\n this.active_child = React.createRef()\n this.state = {\n current_action: null,\n current_vals: []\n }\n }\n\n onActionChanged(new_action) {\n this.setState({\n current_action: new_action.value,\n current_vals: [],\n })\n }\n\n onChange(vals) {\n this.setState({\n current_vals: vals\n })\n }\n\n onApply() {\n const selected = this.props.secondaryOptions[this.state.current_action]\n if(selected) {\n selected.onApply(this.state.current_vals)\n }\n }\n\n render() {\n const selected = this.props.secondaryOptions[this.state.current_action]\n const SecondaryComponent = selected && selected.component\n const apply_disabled = !this.state.current_action || (Array.isArray(this.state.current_vals) && !this.state.current_vals.length) || !this.state.current_vals\n return \n
\n o.value == this.state.current_action)}\n options={this.props.primaryOptions} onChange={(val) => this.onActionChanged(val)} />\n
\n {selected &&\n
\n this.onChange(vals)}/>\n
\n }\n {!selected &&\n
\n \n
\n }\n
this.onApply()}>Apply \n
\n }\n}\n\nexport const IndexView = observer(\n ({store}) => {\n const programOptions = store.program_selections\n const bulk_actions = {\n primary_options: [\n {label: gettext('Set account status'), value: 'set_account_status'},\n {label: gettext('Add to program'), value: 'add_to_program'},\n {label: gettext('Remove from program'), value: 'remove_from_program'},\n ],\n secondary_options: {\n set_account_status: {\n component: (props) => ,\n onApply: (option) => store.bulkUpdateUserStatus(option.value)\n },\n add_to_program: {\n component: (props) => ,\n onApply: (vals) => store.bulkAddPrograms(vals.map(option => option.value))\n },\n remove_from_program: {\n component: (props) => ,\n onApply: (vals) => store.bulkRemovePrograms(vals.map(option => option.value))\n },\n }\n }\n\n return \n
\n \n
\n
\n
\n
\n {gettext(\"Organization\")} \n store.changeOrganizationFilter(e)}\n isMulti={true}\n placeholder={selection_placeholder}\n id=\"organization_filter\" />\n
\n
\n {gettext(\"Status\")} \n store.changeUserStatusFilter(e)}\n placeholder={selection_placeholder}\n id=\"status_filter\" />\n
\n
\n {gettext(\"Admin Role\")} \n store.changeAdminRoleFilter(e)}\n placeholder={selection_placeholder}\n id=\"admin_role_filter\" />\n
\n
\n
\n store.applyFilters()}>{gettext(\"Apply\")} \n store.clearFilters()}>{gettext(\"Reset\")} \n
\n
\n \n
\n
\n
\n \n \n
\n
{store.users_count?`${store.users_count} ${gettext(\"users\")}`:`--`}
\n
\n {store.total_pages &&\n
store.changePage(page)} />\n }\n \n
\n
\n
\n }\n)\n","import { observable, computed, action, runInAction } from \"mobx\";\nimport api from './api';\n\nconst default_user = {\n id: null,\n first_name: \"\",\n last_name: \"\",\n email: \"\",\n phone_number: \"\",\n organization_id: null,\n mode_of_contact: \"\",\n title: \"\",\n user_programs: 0,\n user: {is_active:true},\n}\n\nconst default_editing_target_data = {\n profile: {...default_user},\n access: {country: {}, programs:[]},\n history: []\n}\n\nexport class UserStore {\n @observable users = {}\n @observable users_listing = []\n @observable users_count = null\n @observable fetching_users_listing = false\n @observable current_page = 0\n @observable total_pages = null\n @observable bulk_targets = new Map()\n @observable bulk_targets_all = false\n @observable applying_bulk_updates = false\n\n @observable saving_user_profile = false\n @observable saving_user_programs = false\n\n @observable access = {countries: {}, programs: {}}\n @observable is_superuser = false\n\n @observable fetching_editing_target = false\n @observable editing_target = null\n @observable editing_target_data = {...default_editing_target_data}\n @observable editing_errors = {}\n\n @observable new_user = null\n\n //filter options\n @observable countries = {}\n @observable ordered_country_ids = []\n @observable organizations = {}\n @observable programs = {}\n @observable available_users = []\n\n @observable countries_selections = []\n @observable organization_selections = []\n @observable program_selections = []\n @observable user_selections = []\n @observable program_bulk_selections = []\n\n country_role_choices = []\n program_role_choices = []\n\n user_status_options = [\n {value: 1, label: 'Active'},\n {value: 0, label: 'Inactive'}\n ]\n\n admin_role_options = [\n {value: 1, label: 'Yes'},\n {value: 0, label: 'No'}\n ]\n\n @observable filters = {\n countries: [],\n base_countries: [],\n organizations: [],\n programs: [],\n user_status: '',\n admin_role: '',\n users: []\n }\n\n constructor({\n countries,\n organizations,\n programs,\n users,\n access,\n is_superuser,\n programs_filter,\n country_filter,\n organizations_filter,\n program_role_choices,\n country_role_choices,\n }) {\n this.countries = countries\n this.ordered_country_ids = Object.values(countries).sort((a, b) => a.name.localeCompare(b.name)).map(country => country.id)\n this.organizations = organizations\n this.programs = programs\n this.available_users = users.filter(user => user.name)\n\n this.countries_selections = this.ordered_country_ids.map(id => this.countries[id])\n .map(country => ({value: country.id, label: country.name}))\n\n this.organization_selections = Object.values(organizations).map(org => ({value: org.id, label: org.name}))\n\n this.program_selections = this.createProgramSelections(this.programs)\n\n this.user_selections = this.available_users.map(user => ({value: user.id, label: user.name}))\n\n this.program_bulk_selections = this.ordered_country_ids.map(id => this.countries[id]).map((country) => ({\n label: country.name,\n options: country.programs.map(program_id => ({\n label: country.name+\": \"+programs[program_id].name,\n value: country.id+\"_\"+program_id\n }))\n }))\n\n this.access = access\n this.is_superuser = is_superuser\n this.filters.programs = programs_filter.map(id => this.programs[id]).map(program => ({label: program.name, value: program.id}))\n this.filters.organizations = organizations_filter.map(id => this.organizations[id]).map(org => ({label: org.name, value: org.id}))\n this.filters.countries = country_filter.map(id => this.countries[id]).map(country => ({label: country.name, value: country.id}))\n\n this.country_role_choices = country_role_choices.map(([value, label]) => ({label, value}))\n this.program_role_choices = program_role_choices.map(([value, label]) => ({label, value}))\n this.fetchUsers()\n }\n\n /*******************\n we turn the complex intermediate filter objects into simple lists for\n transmission to the api, (while retaining their filter keys)\n\n eg\n\n {\n ...\n countries: [{label: 'Afghanistan', value: 1}]\n }\n\n becomes\n\n {\n ...\n countries: [1]\n }\n\n */\n marshalFilters(filters) {\n return Object.entries(filters).reduce((xs, x) => {\n if(Array.isArray(x[1])) {\n xs[x[0]] = x[1].map(x => x.value)\n } else {\n xs[x[0]] = x[1].value\n }\n return xs\n }, {})\n }\n\n getSelectedBulkTargetIDs() {\n return [...this.bulk_targets.entries()]\n .filter(([_, selected]) => selected)\n .map(([user_id, _]) => user_id)\n }\n\n onSaveErrorHandler(message) {\n PNotify.error({text: message || gettext('Saving Failed'), delay: 5000});\n }\n\n onSaveSuccessHandler(message) {\n PNotify.success({text: message || gettext('Successfully Saved'), delay: 5000})\n }\n\n createProgramSelections(programs) {\n return Object.values(programs).map(program => ({value: program.id, label: program.name}))\n }\n\n @action\n fetchUsers() {\n this.fetching_users_listing = true\n api.fetchUsersWithFilter(this.current_page + 1, this.marshalFilters(this.filters)).then(results => {\n runInAction(() => {\n this.fetching_users_listing = false\n this.users = results.users.reduce((xs, x) => {\n xs[x.id] = x\n return xs\n }, {})\n this.users_listing = results.users.map(u => u.id)\n this.bulk_targets_all = false\n this.bulk_targets = new Map()\n this.users_count = results.total_users\n this.total_pages = results.total_pages\n this.next_page = results.next_page\n this.previous_page = results.previous_page\n })\n })\n }\n\n @action\n applyFilters() {\n this.current_page = 0\n this.fetchUsers()\n }\n\n @action\n changePage(page) {\n if(page.selected != this.current_page) {\n this.current_page = page.selected\n this.fetchUsers()\n }\n }\n\n @action\n toggleBulkTargetsAll() {\n this.bulk_targets_all = !this.bulk_targets_all\n let user_ids = Object.values(this.users_listing)\n this.bulk_targets = new Map(user_ids.map(id => [id, this.bulk_targets_all]))\n }\n\n @action\n toggleBulkTarget(target_id) {\n this.bulk_targets.set(target_id, !this.bulk_targets.get(target_id))\n }\n\n @action\n changeCountryFilter(countries) {\n this.filters.countries = countries\n if(countries.length == 0) {\n this.program_selections = this.createProgramSelections(this.programs)\n } else {\n const candidate_programs = countries.map(selection => selection.value)\n .map(id => this.countries[id])\n .flatMap(country => country.programs)\n const selected_programs_set = new Set(candidate_programs)\n this.program_selections = this.createProgramSelections(Array.from(selected_programs_set).map(id => this.programs[id]))\n }\n }\n\n @action\n changeBaseCountryFilter(base_countries) {\n this.filters.base_countries = base_countries\n }\n\n @action\n changeOrganizationFilter(organizations) {\n this.filters.organizations = organizations\n }\n\n @action\n changeProgramFilter(programs) {\n this.filters.programs = programs\n }\n\n @action\n changeUserStatusFilter(status) {\n this.filters.user_status = status\n }\n\n @action\n changeAdminRoleFilter(role) {\n this.filters.admin_role = role\n }\n\n @action\n changeUserFilter(users) {\n this.filters.users = users\n }\n\n @action\n toggleEditingTarget(user_id) {\n this.editing_errors = {}\n this.editing_target_data = {...default_editing_target_data}\n if(this.editing_target == 'new') {\n this.users_listing.shift()\n }\n\n if(this.editing_target == user_id) {\n this.editing_target = null\n } else {\n this.editing_target = user_id\n this.fetching_editing_target = true\n Promise.all([api.fetchUser(user_id), api.fetchUserProgramAccess(user_id), api.fetchUserHistory(user_id)]).then(([user, access_data, history_data]) => {\n runInAction(() => {\n this.fetching_editing_target = false\n this.editing_target_data = {\n profile: user,\n access: access_data,\n history: history_data\n }\n })\n })\n }\n }\n\n @action\n updateActiveEditPage(section_name) {\n this.active_edit_page = section_name\n }\n\n @action\n createUser() {\n this.editing_errors = {}\n if(this.editing_target == 'new') {\n this.users_listing.shift()\n }\n\n this.editing_target_data = {...default_editing_target_data}\n\n this.users[\"new\"] = {\n id: \"new\",\n name: \"\",\n organization_name: \"\",\n user_programs: 0,\n is_admin: false,\n is_active: false\n }\n\n this.users_listing.unshift(\"new\")\n this.editing_target = 'new'\n }\n\n @action\n updateUserProfile(user_id, new_user_data) {\n this.saving_user_profile = true\n this.editing_errors = {}\n api.saveUserProfile(user_id, new_user_data).then(result => Promise.all([api.fetchUserAggregates(result.id), api.fetchUserHistory(result.id)]).then(([aggregates, history]) => {\n this.onSaveSuccessHandler()\n runInAction(() => {\n this.saving_user_profile = false\n this.users[result.id] = {\n id: result.id,\n name: result.name,\n organization_name: this.organizations[result.organization_id].name,\n user_programs: aggregates.program_count,\n is_admin: result.user.is_staff,\n is_active: result.user.is_active\n }\n this.editing_target_data.profile = result\n this.editing_target_data.history = history\n })\n })).catch(errors => {\n this.onSaveErrorHandler(errors.response.data.detail)\n runInAction(() => {\n this.saving_user_profile = false\n this.editing_errors = errors.response.data\n })\n })\n }\n\n @action\n updateUserIsActive(user_id, new_user_data) {\n this.saving_user_profile = true\n this.editing_errors = {}\n api.updateUserIsActive(user_id, new_user_data).then(result => Promise.all([api.fetchUserAggregates(user_id), api.fetchUserHistory(user_id)]).then(([aggregates, history]) => {\n this.onSaveSuccessHandler()\n runInAction(() => {\n this.saving_user_profile = false\n this.users[result.id] = {\n id: result.id,\n name: result.name,\n organization_name: this.organizations[result.organization_id].name,\n user_programs: aggregates.program_count,\n is_admin: result.user.is_staff,\n is_active: result.user.is_active\n }\n this.editing_target_data.profile = result\n this.editing_target_data.history = history\n })\n })).catch(errors => {\n this.onSaveErrorHandler(errors.response.data.detail)\n runInAction(() => {\n this.saving_user_profile = false\n this.editing_errors = errors.response.data\n })\n })\n }\n\n @action\n resendRegistrationEmail(user_id) {\n this.saving_user_profile = true\n api.resendRegistrationEmail(user_id).then(result => {\n runInAction(() => {\n this.saving_user_profile = false\n this.onSaveSuccessHandler(gettext(\"Verification email sent\"))\n })\n }).catch(() => {\n this.onSaveSuccessHandler(gettext(\"Verification email send failed\"))\n })\n }\n\n @action\n saveNewUser(new_user_data) {\n this.saving_user_profile = true\n this.editing_errors = {}\n api.createUser(new_user_data).then(result => api.fetchUserAggregates(result.id).then(aggregates => {\n this.onSaveSuccessHandler()\n runInAction(() => {\n this.saving_user_profile = false\n this.users[result.id] = {\n id: result.id,\n name: result.name,\n organization_name: this.organizations[result.organization_id].name,\n user_programs: aggregates.program_count,\n is_admin: result.user.is_staff,\n is_active: result.user.is_active\n }\n this.user_selections.push({value: result.id, label: result.name})\n this.users_listing[0] = result.id\n this.editing_target = null\n this.toggleEditingTarget(result.id)\n delete this.users[\"new\"]\n })\n })).catch(errors => {\n this.onSaveErrorHandler(errors.response.data.detail)\n runInAction(() => {\n this.saving_user_profile = false\n this.editing_errors = errors.response.data\n })\n })\n }\n\n @action\n saveNewUserAndAddAnother(new_user_data) {\n this.saving_user_profile = true\n this.editing_errors = {}\n api.createUser(new_user_data).then(result => api.fetchUserAggregates(result.id).then(aggregates => {\n this.onSaveSuccessHandler()\n runInAction(() => {\n this.saving_user_profile = false\n this.users[result.id] = {\n id: result.id,\n name: result.name,\n organization_name: this.organizations.find(o => o.id = result.organization_id).name,\n user_programs: aggregates.program_count,\n is_admin: result.user.is_staff,\n is_active: result.user.is_active\n }\n this.users_listing[0] = result.id\n delete this.users[\"new\"]\n this.createUser()\n })\n })).catch(errors => {\n this.onSaveErrorHandler(errors.response.data.detail)\n runInAction(() => {\n this.saving_user_profile = false\n this.editing_errors = errors.response.data\n })\n })\n }\n\n @action\n saveUserPrograms(user_id, new_user_programs_data) {\n this.saving_user_programs = true\n api.saveUserPrograms(user_id, new_user_programs_data).then(result => Promise.all([api.fetchUserAggregates(user_id), api.fetchUserHistory(user_id), api.fetchUserProgramAccess(user_id)]).then(([aggregates, history, access]) => {\n runInAction(() => {\n this.saving_user_programs = false\n this.users[user_id].user_programs = aggregates.program_count\n this.editing_target_data.history = history\n this.editing_target_data.access = access\n })\n this.onSaveSuccessHandler()\n })).catch(errors => {\n this.onSaveErrorHandler(errors.response.data.detail)\n runInAction(() => {\n this.saving_user_programs = false\n })\n })\n }\n\n @action\n bulkUpdateUserStatus(new_status) {\n this.applying_bulk_updates = true\n api.bulkUpdateUserStatus(\n this.getSelectedBulkTargetIDs(),\n new_status\n ).then(result => {\n runInAction(() => {\n result.forEach(updated => {\n let user = Object.assign(this.users[updated.id], updated)\n this.users[user.id] = user\n })\n this.applying_bulk_updates = false\n })\n this.onSaveSuccessHandler()\n }).catch(response => {\n runInAction(() => {\n this.applying_bulk_updates = false\n })\n this.onSaveErrorHandler()\n })\n }\n\n @action\n bulkAddPrograms(added_programs) {\n this.applying_bulk_updates = true\n api.bulkAddPrograms(\n this.getSelectedBulkTargetIDs(),\n added_programs.map(key => {\n const [country_id, program_id] = key.split('_')\n return {country: country_id, program: program_id, role: 'low'}\n })\n ).then(result => {\n //update open user programs\n const updated_users = this.getSelectedBulkTargetIDs()\n updated_users.forEach(id => {\n if(this.editing_target == id) {\n api.fetchUserProgramAccess(id).then(access => {\n runInAction(() => {\n this.editing_target_data.access = access\n })\n })\n }\n })\n\n runInAction(() => {\n Object.entries(result).forEach(([id, count]) => {\n this.users[id].user_programs = count\n })\n this.applying_bulk_updates = false\n })\n this.onSaveSuccessHandler()\n }).catch(response => {\n runInAction(() => {\n this.applying_bulk_updates = false\n })\n this.onSaveErrorHandler()\n })\n }\n\n @action\n bulkRemovePrograms(removed_programs) {\n this.applying_bulk_updates = true\n api.bulkRemovePrograms(\n this.getSelectedBulkTargetIDs(),\n removed_programs.map(key => {\n const [country_id, program_id] = key.split('_')\n return {country: country_id, program: program_id, role: 'low'}\n })\n ).then(result => {\n //update open user programs\n const updated_users = this.getSelectedBulkTargetIDs()\n updated_users.forEach(id => {\n if(this.editing_target == id) {\n api.fetchUserProgramAccess(id).then(access => {\n runInAction(() => {\n this.editing_target_data.access = access\n })\n })\n }\n })\n\n runInAction(() => {\n Object.entries(result).forEach(([id, count]) => {\n this.users[id].user_programs = count\n })\n this.applying_bulk_updates = false\n })\n\n this.onSaveSuccessHandler()\n }).catch(response => {\n runInAction(() => {\n this.applying_bulk_updates = false\n })\n this.onSaveErrorHandler()\n })\n }\n\n @action\n clearFilters() {\n this.filters = {\n countries: [],\n base_countries: [],\n organizations: [],\n programs: [],\n user_status: '',\n admin_role: '',\n users: []\n }\n }\n}\n","import React from 'react'\nimport { observer } from \"mobx-react\"\n\n@observer\nexport default class UserEditor extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n active_page: 'profile'\n }\n }\n\n updateActivePage(new_page) {\n if(!this.props.new) {\n this.setState({active_page: new_page})\n }\n }\n\n render() {\n const {ProfileSection, ProgramSection, HistorySection} = this.props\n\n const profile_active_class = (this.state.active_page == 'profile')?'active':''\n const programs_active_class = (this.state.active_page == 'programs_and_roles')?'active':''\n const history_active_class = (this.state.active_page == 'status_and_history')?'active':''\n const new_class = (this.props.new)?'disabled':''\n\n return (\n \n
\n
\n {this.state.active_page == 'profile' &&\n
\n }\n\n {this.state.active_page == 'programs_and_roles' &&\n
\n }\n\n {this.state.active_page == 'status_and_history' &&\n
\n }\n
\n
\n )\n }\n}\n","import React from 'react'\n\nclass Expander extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n folded: false,\n }\n }\n\n toggleFolded() {\n this.setState({\n folded: !this.state.folded\n })\n }\n\n render() {\n const {className, ...props} = this.props\n const icon = (this.state.folded)?\"fa-chevron-right\":\"fa-chevron-left\"\n return \n {!this.state.folded &&\n
{this.props.children} \n }\n\n
this.toggleFolded()}>\n \n
\n
\n }\n}\n\nexport default Expander\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAIA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAPA;AAAA;AADA;AACA;AAWA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAIA;AACA;AALA;AAAA;AADA;AACA;AACA;AASA;AAAA;AAAA;AAIA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AALA;AAAA;AACA;AAQA;AACA;AACA;AACA;AACA;AAFA;AAIA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAFA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AACA;AAIA;AAAA;AAEA;AAAA;AACA;AAAA;AAHA;AACA;AAQA;;;;;AACA;AAAA;AACA;AADA;AACA;AAAA;AADA;AAIA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAXA;AAPA;AAoBA;AACA;;;AACA;AAAA;AAEA;AACA;AAEA;AACA;AANA;AAAA;AAAA;AACA;AAeA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AATA;AAWA;;;AAEA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AAPA;AASA;;;AAEA;AACA;AACA;AACA;AACA;AAFA;AADA;AAOA;;;AAEA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AADA;AAAA;AAAA;AAAA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAFA;AADA;AASA;;;AAEA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAFA;AADA;AAMA;;;AAEA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAFA;AADA;AASA;;;AAEA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAJA;AAMA;AACA;AACA;AACA;AACA;AACA;AAJA;AAMA;AACA;AACA;AACA;AACA;AAEA;AAFA;AADA;AASA;;;AAEA;AACA;AACA;AACA;AAHA;AAAA;AAAA;AACA;AAQA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAJA;AAMA;;;AAEA;AACA;AACA;AAFA;AAAA;AAAA;AACA;AAOA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAJA;AAMA;;;AAEA;AACA;AACA;AAFA;AAAA;AAAA;AACA;AAOA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAHA;AAKA;;;AAEA;AAAA;AACA;AADA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAUA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AADA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAOA;AAAA;AAEA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AANA;AASA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AALA;AAAA;AAOA;AAAA;AACA;AAAA;AACA;AAKA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AA1BA;AA6BA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAZA;AAeA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AALA;AAAA;AAOA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAHA;AAIA;AAAA;AAAA;AAAA;AAAA;AALA;AAZA;AAnDA;AA6EA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA;;;;AA5aA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/EA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AACA;AAAA;AACA;AACA;AACA;AAFA;AAIA;AANA;AAOA;AACA;AATA;AAAA;AAAA;AAUA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAFA;AARA;AAaA;AAKA;AA5CA;AACA;AADA;AAAA;AACA;AA8CA;AAAA;AAEA;AACA;AADA;AADA;AADA;AACA;AAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3DA;AACA;AACA;AACA;AAEA;;;;;AACA;AAAA;AACA;AADA;AACA;AAAA;AADA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAJA;AAXA;AAiBA;AACA;;;AAEA;AACA;AACA;AACA;;;AAEA;AACA;AACA;AACA;;;AAEA;AACA;AACA;AACA;;;AAEA;AACA;AACA;AAEA;AAFA;AADA;AAMA;;;AAEA;AACA;AACA;AAEA;AAFA;AADA;AAMA;;;AAEA;AACA;AACA;AAEA;AAFA;AAIA;AALA;AAOA;;;AAEA;AACA;AACA;AAEA;AAFA;AADA;AAMA;;;AAEA;AACA;AACA;AAEA;AAFA;AADA;AAMA;;;AAEA;AACA;AACA;AAEA;AAFA;AADA;AAMA;;;AAEA;AACA;AACA;AAEA;AAFA;AADA;AAMA;;;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAFA;AAIA;;;AAEA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAJA;AAMA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;A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AEA;AANA;AAYA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAFA;AAJA;AADA;AAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AALA;AAOA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AALA;AAOA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AALA;AAOA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AALA;AAOA;AACA;AACA;;;;;AACA;AAAA;AACA;AADA;AACA;AAAA;AACA;AACA;AADA;AAFA;AAKA;AACA;;;AACA;AACA;AACA;AADA;AAGA;;;AAEA;AACA;AACA;;;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;;;;AApBA;AACA;AAsBA;;;;;AACA;AAAA;AACA;AADA;AACA;AAAA;AACA;AACA;AADA;AAFA;AAKA;AACA;;;AACA;AACA;AACA;AADA;AAGA;;;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;;;;AAhBA;AACA;AAkBA;;;;;AACA;AAAA;AACA;AADA;AACA;AAAA;AACA;AACA;AACA;AACA;AAFA;AAHA;AAOA;AACA;;;AACA;AACA;AACA;AACA;AAFA;AAIA;;;AAEA;AACA;AACA;AADA;AAGA;;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;;;AAEA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAHA;AAMA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA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HA;AAKA;AACA;AACA;AACA;AA9QA;AAAA;AAAA;AAkRA;AACA;AAnRA;AAAA;AAAA;AAuRA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AASA;AACA;AACA;AAzSA;AAAA;AAAA;AA4SA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAQA;AACA;AACA;AACA;AAfA;AAgBA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AArUA;AAAA;AAAA;AAwUA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAQA;AACA;AACA;AACA;AAfA;AAgBA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAjWA;AAAA;AAAA;AAoWA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AA9WA;AAAA;AAAA;AAiXA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AACA;AAOA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAlBA;AAmBA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AA7YA;AAAA;AAAA;AAgZA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AANA;AAQA;AACA;AACA;AAAA;AACA;AACA;AAhBA;AAiBA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AA1aA;AAAA;AAAA;AA6aA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AARA;AASA;AACA;AAAA;AACA;AACA;AACA;AACA;AA7bA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","sourceRoot":""}
\ No newline at end of file
diff --git a/build/dev-dist/tola_management_user-2e62a5cc5ee41288dcc0.js b/build/dev-dist/tola_management_user-3a98142a4e1ec567b01d.js
similarity index 94%
rename from build/dev-dist/tola_management_user-2e62a5cc5ee41288dcc0.js
rename to build/dev-dist/tola_management_user-3a98142a4e1ec567b01d.js
index 12384a4f..a74b3746 100644
--- a/build/dev-dist/tola_management_user-2e62a5cc5ee41288dcc0.js
+++ b/build/dev-dist/tola_management_user-3a98142a4e1ec567b01d.js
@@ -1333,7 +1333,7 @@ __webpack_require__.r(__webpack_exports__);
/* harmony import */ var mobx_react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! mobx-react */ "okNM");
/* harmony import */ var react_select__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! react-select */ "y2Vs");
/* harmony import */ var react_virtualized__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! react-virtualized */ "c7k8");
-/* harmony import */ var components_expander__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! components/expander */ "H4hL");
+/* harmony import */ var components_changelog__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! components/changelog */ "KnAV");
function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
@@ -1352,14 +1352,6 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function"
function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
-function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
-
-function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
-
-function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
-
-function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
-
@@ -1372,38 +1364,6 @@ var status_options = [{
value: false,
label: gettext('Inactive')
}];
-
-var ChangesetEntry = function ChangesetEntry(_ref) {
- var name = _ref.name,
- type = _ref.type,
- data = _ref.data;
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("strong", null, name), ": ", data != undefined && data != null ? data.toString() : 'N/A');
-};
-
-var ProgramChangesetEntry = function ProgramChangesetEntry(_ref2) {
- var data = _ref2.data,
- timeframe = _ref2.timeframe;
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, Object.entries(data.countries).length > 0 && react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("h3", null, "Countries"), Object.entries(data.countries).map(function (_ref3) {
- var _ref4 = _slicedToArray(_ref3, 2),
- id = _ref4[0],
- country = _ref4[1];
-
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
- key: id,
- className: "program-changeset-row"
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("strong", null, gettext("Country")), ": ", country[timeframe].country), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("strong", null, gettext("Role")), ": ", country[timeframe].role));
- })), Object.entries(data.programs).length > 0 && react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("h3", null, "Programs"), Object.entries(data.programs).map(function (_ref5) {
- var _ref6 = _slicedToArray(_ref5, 2),
- id = _ref6[0],
- program = _ref6[1];
-
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
- key: id,
- className: "program-changeset-row"
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("strong", null, gettext("Program")), ": ", program[timeframe].program), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("strong", null, gettext("Country")), ": ", program[timeframe].country), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("p", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("strong", null, gettext("Role")), ": ", program[timeframe].role));
- })));
-};
-
var EditUserHistory =
/*#__PURE__*/
function (_React$Component) {
@@ -1498,51 +1458,9 @@ function (_React$Component) {
onClick: function onClick() {
return _this2.onReset();
}
- }, gettext("Reset")))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("table", {
- className: "table table-sm text-small"
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("thead", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("Date")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("Admin")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("Change Type")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("Previous Entry")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", null, gettext("New Entry")))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tbody", null, history.map(function (entry) {
- if (entry.change_type == 'user_programs_updated') {
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", {
- key: entry.id
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
- className: "text-nowrap"
- }, entry.date), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, entry.admin_user), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, entry.change_type), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
- className: "expand-section"
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(components_expander__WEBPACK_IMPORTED_MODULE_4__["default"], null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ProgramChangesetEntry, {
- data: entry.diff_list,
- timeframe: "prev"
- }))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
- className: "expand-section"
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(components_expander__WEBPACK_IMPORTED_MODULE_4__["default"], null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ProgramChangesetEntry, {
- data: entry.diff_list,
- timeframe: "new"
- }))));
- } else {
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", {
- key: entry.id
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
- className: "text-nowrap"
- }, entry.date), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, entry.admin_user), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, entry.change_type), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
- className: "expand-section"
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(components_expander__WEBPACK_IMPORTED_MODULE_4__["default"], null, entry.diff_list.map(function (changeset) {
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangesetEntry, {
- key: changeset.name,
- name: changeset.name,
- type: entry.change_type,
- data: changeset.prev
- });
- }))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
- className: "expand-section"
- }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(components_expander__WEBPACK_IMPORTED_MODULE_4__["default"], null, entry.diff_list.map(function (changeset) {
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangesetEntry, {
- key: changeset.name,
- name: changeset.name,
- type: entry.change_type,
- data: changeset.new
- });
- }))));
- }
- }))));
+ }, gettext("Reset")))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(components_changelog__WEBPACK_IMPORTED_MODULE_4__["default"], {
+ data: history
+ }));
}
}]);
@@ -1552,10 +1470,10 @@ function (_React$Component) {
/***/ }),
-/***/ "H4hL":
-/*!***********************************!*\
- !*** ./js/components/expander.js ***!
- \***********************************/
+/***/ "KnAV":
+/*!************************************!*\
+ !*** ./js/components/changelog.js ***!
+ \************************************/
/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
@@ -1563,86 +1481,159 @@ function (_React$Component) {
__webpack_require__.r(__webpack_exports__);
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "q1tI");
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
-function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
-
-function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
-
-function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
-
-function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
-
-function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
-
-function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
-
-function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
+function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); }
-function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
+function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); }
-function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
+function _iterableToArrayLimit(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
+function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
-var Expander =
-/*#__PURE__*/
-function (_React$Component) {
- _inherits(Expander, _React$Component);
- function Expander(props) {
- var _this;
+var ChangeField = function ChangeField(_ref) {
+ var name = _ref.name,
+ data = _ref.data;
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "change__field"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("strong", null, name), ": ", data != undefined && data != null ? data.toString() : 'N/A');
+};
- _classCallCheck(this, Expander);
+var ChangeLogEntryHeader = function ChangeLogEntryHeader(_ref2) {
+ var data = _ref2.data;
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", {
+ className: "changelog__entry__header is-expanded"
+ }, " ", react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
+ className: "text-nowrap text-action"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("i", {
+ className: "fas fa-caret-down"
+ }), "\xA0", react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("strong", null, data.date)), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
+ className: "text-nowrap"
+ }, data.admin_user), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, data.change_type), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null));
+};
- _this = _possibleConstructorReturn(this, _getPrototypeOf(Expander).call(this, props));
- _this.state = {
- expanded: false,
- overflowing: false
- };
- _this.ref = react__WEBPACK_IMPORTED_MODULE_0___default.a.createRef();
- return _this;
- }
+var ChangeLogEntryRow = function ChangeLogEntryRow(_ref3) {
+ var data = _ref3.data;
- _createClass(Expander, [{
- key: "componentDidMount",
- value: function componentDidMount() {
- if (this.ref.current.scrollHeight > this.ref.current.clientHeight) {
- this.setState({
- overflowing: true
- });
- }
- }
- }, {
- key: "toggleExpanded",
- value: function toggleExpanded(e) {
- e.preventDefault();
- this.setState({
- expanded: !this.state.expanded
+ if (data.change_type == 'user_programs_updated') {
+ // Create multiple row for program/country changes:
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(react__WEBPACK_IMPORTED_MODULE_0___default.a.Fragment, null, Object.entries(data.diff_list.countries).length > 0 && Object.entries(data.diff_list.countries).map(function (_ref4) {
+ var _ref5 = _slicedToArray(_ref4, 2),
+ id = _ref5[0],
+ country = _ref5[1];
+
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", {
+ key: id,
+ className: "changelog__entry__row"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog__change--prev"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "country",
+ data: country.prev.country
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "role",
+ data: country.prev.role
+ }))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog__change--new"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "country",
+ data: country.new.country
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "role",
+ data: country.new.role
+ }))));
+ }), Object.entries(data.diff_list.programs).length > 0 && Object.entries(data.diff_list.programs).map(function (_ref6) {
+ var _ref7 = _slicedToArray(_ref6, 2),
+ id = _ref7[0],
+ program = _ref7[1];
+
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", {
+ key: id,
+ className: "changelog__entry__row"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog__change--prev"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "program",
+ data: program.prev.program
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "country",
+ data: program.prev.country
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "role",
+ data: program.prev.role
+ }))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog__change--new"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "program",
+ data: program.new.program
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "country",
+ data: program.new.country
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ name: "role",
+ data: program.new.role
+ }))));
+ }));
+ } else {
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", {
+ className: "changelog__entry__row"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", {
+ className: "text-nowrap"
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog__change--prev"
+ }, data.diff_list.map(function (changeset, id) {
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ key: id,
+ name: changeset.name,
+ data: changeset.prev
});
- }
- }, {
- key: "render",
- value: function render() {
- var _this2 = this;
+ }))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("td", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
+ className: "changelog__change--new"
+ }, data.diff_list.map(function (changeset, id) {
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeField, {
+ key: id,
+ name: changeset.name,
+ data: changeset.new
+ });
+ }))));
+ }
+};
- return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
- ref: this.ref,
- className: "expander",
- style: {
- height: !this.state.expanded && (this.props.height || 50)
- }
- }, this.props.children), this.state.overflowing && react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("a", {
- href: "",
- onClick: function onClick(e) {
- return _this2.toggleExpanded(e);
- }
- }, this.state.expanded ? 'Show Less' : 'Show More')));
- }
- }]);
+var ChangeLogEntry = function ChangeLogEntry(_ref8) {
+ var data = _ref8.data;
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tbody", {
+ className: "changelog__entry",
+ key: data.id
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeLogEntryHeader, {
+ data: data
+ }), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeLogEntryRow, {
+ data: data
+ }));
+};
- return Expander;
-}(react__WEBPACK_IMPORTED_MODULE_0___default.a.Component);
+var ChangeLog = function ChangeLog(_ref9) {
+ var data = _ref9.data;
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("table", {
+ className: "table table-sm bg-white table-bordered text-small changelog"
+ }, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("thead", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("tr", null, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap"
+ }, gettext("Date")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap"
+ }, gettext("Admin")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap"
+ }, gettext("Change Type")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap td--half-stretch"
+ }, gettext("Previous Entry")), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("th", {
+ className: "text-nowrap td--half-stretch"
+ }, gettext("New Entry")))), data.map(function (entry, id) {
+ return react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(ChangeLogEntry, {
+ key: id,
+ data: entry
+ });
+ }));
+};
-/* harmony default export */ __webpack_exports__["default"] = (Expander);
+/* harmony default export */ __webpack_exports__["default"] = (ChangeLog);
/***/ }),
@@ -2491,7 +2482,7 @@ var IndexView = Object(mobx_react__WEBPACK_IMPORTED_MODULE_1__["observer"])(func
}
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("i", {
className: "fas fa-plus-circle"
- }), gettext("Add User"), gettext("Add User")))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(components_loading_spinner__WEBPACK_IMPORTED_MODULE_10__["default"], {
+ }), gettext("Add User")))), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement(components_loading_spinner__WEBPACK_IMPORTED_MODULE_10__["default"], {
isLoading: store.fetching_users_listing || store.applying_bulk_updates
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
className: "admin-list__table"
@@ -3789,7 +3780,7 @@ function (_React$Component) {
className: "nav-item"
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("a", {
href: "#",
- className: "nav-link ".concat(programs_active_class, " ").concat(new_class),
+ className: "nav-link text-nowrap ".concat(programs_active_class, " ").concat(new_class),
onClick: function onClick(e) {
e.preventDefault();
@@ -3799,7 +3790,7 @@ function (_React$Component) {
className: "nav-item"
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("a", {
href: "#",
- className: "nav-item nav-link ".concat(history_active_class, " ").concat(new_class),
+ className: "nav-link text-nowrap ".concat(history_active_class, " ").concat(new_class),
onClick: function onClick(e) {
e.preventDefault();
@@ -3912,4 +3903,4 @@ function (_React$Component) {
/***/ })
},[["9KAa","runtime","vendors"]]]);
-//# sourceMappingURL=tola_management_user-2e62a5cc5ee41288dcc0.js.map
\ No newline at end of file
+//# sourceMappingURL=tola_management_user-3a98142a4e1ec567b01d.js.map
\ No newline at end of file
diff --git a/build/dev-dist/tola_management_user-3a98142a4e1ec567b01d.js.map b/build/dev-dist/tola_management_user-3a98142a4e1ec567b01d.js.map
new file mode 100644
index 00000000..704060d9
--- /dev/null
+++ b/build/dev-dist/tola_management_user-3a98142a4e1ec567b01d.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"tola_management_user-3a98142a4e1ec567b01d.js","sources":["webpack:///./js/pages/tola_management_pages/user/components/edit_user_programs.js","webpack:///./js/components/virtualized-react-select.js","webpack:///./js/pages/tola_management_pages/user/components/edit_user_profile.js","webpack:///./js/pages/tola_management_pages/user/index.js","webpack:///./js/components/loading-spinner.js","webpack:///./js/pages/tola_management_pages/user/components/edit_user_history.js","webpack:///./js/components/changelog.js","webpack:///./js/pages/tola_management_pages/user/api.js","webpack:///./js/components/pagination.js","webpack:///./js/components/management-table.js","webpack:///./js/api.js","webpack:///./js/components/checkboxed-multi-select.js","webpack:///./js/pages/tola_management_pages/user/views.js","webpack:///./js/pages/tola_management_pages/user/models.js","webpack:///./js/pages/tola_management_pages/user/components/user_editor.js","webpack:///./js/components/folding-sidebar.js"],"sourcesContent":["import React from 'react'\nimport { observer } from \"mobx-react\"\nimport {AutoSizer, Table, Column, CellMeasurer, CellMeasurerCache} from 'react-virtualized'\nimport Select from 'components/virtualized-react-select'\n\n//we need a pretty peculiar structure to accommodate the virtualized table\nconst create_country_objects = (countries, store) => Object.entries(countries)\n .reduce((countries, [id, country]) => ({\n ...countries,\n [id]: {\n ...country,\n type: 'country',\n options: [{label: '', value: 'none'}, ...store.country_role_choices],\n admin_access: store.is_superuser,\n programs: new Set(country.programs)\n }\n }),{})\n\nconst create_program_objects = (programs, store) => Object.entries(programs)\n .reduce((programs, [id, program]) => ({\n ...programs,\n [id]: {\n ...program,\n type: 'program',\n options: store.program_role_choices,\n }\n }),{})\n\n//we need to flatten the country -> program heirarchy to support the virtualized table\nconst flattened_listing = (countries, programs) => countries.flatMap(country =>\n [\n country,\n ...Array.from(country.programs)\n .filter(program_id => programs[program_id])\n .map(program_id => ({...programs[program_id], id: `${country.id}_${program_id}`, country_id: country.id}))\n ]\n )\n\nconst apply_program_filter = (programs, countries, filter_string) => {\n if(!filter_string) {\n return {\n programs,\n countries\n }\n }\n const filtered_programs = Object.entries(programs).filter(([_, program]) => program.name.toLowerCase().includes(filter_string.toLowerCase())).map(([_, p]) => p)\n const filtered_countries = Object.entries(countries).filter(([_, country]) => filtered_programs.some(program => country.programs.has(program.id))).map(([_, c]) => c)\n\n return {\n countries: filtered_countries.reduce((countries, country) => ({...countries, [country.id]: country}), {}),\n programs: filtered_programs.reduce((programs, program) => ({...programs, [program.id]: program}), {}),\n }\n}\n\nconst apply_country_filter = (countries, filtered) => {\n if(filtered.length > 0) {\n return filtered.filter(option => countries[option.value])\n .map(option => countries[option.value])\n .reduce((countries, country) => ({...countries, [country.id]: country}), {})\n } else {\n return countries\n }\n}\n\nconst create_user_access = (user_access) => ({\n countries: Object.entries(user_access.countries).reduce((countries, [id, country]) => ({...countries, [id]: {...country, has_access: true}}), {}),\n programs: user_access.programs.reduce((programs, program) => ({...programs, [`${program.country}_${program.program}`]: {...program, has_access: true}}), {})\n})\n\nconst country_has_all_access = (country, visible_programs, user_program_access) =>\n Array.from(country.programs)\n .filter(program_id => !!visible_programs[program_id])\n .every(program_id =>\n user_program_access.programs[`${country.id}_${program_id}`]\n && user_program_access.programs[`${country.id}_${program_id}`].has_access\n )\n\n@observer\nexport default class EditUserPrograms extends React.Component {\n constructor(props) {\n super(props)\n const {store} = props\n\n const countries = create_country_objects(store.countries, store)\n const programs = create_program_objects(store.programs, store)\n\n this.state = {\n program_filter: '',\n country_filter: [],\n country_selections: Object.entries(store.countries).map(([_, country]) => ({value: country.id, label: country.name})),\n countries,\n programs,\n filtered_countries: countries,\n filtered_programs: programs,\n ordered_country_ids: store.ordered_country_ids,\n flattened_programs: flattened_listing(store.ordered_country_ids.filter(id => id in countries).map(id => countries[id]), programs),\n original_user_program_access: create_user_access(store.editing_target_data.access),\n user_program_access: create_user_access(store.editing_target_data.access)\n }\n }\n\n componentWillReceiveProps(next_props) {\n const {store} = next_props\n const countries_obj = create_country_objects(store.countries, store)\n const programs_obj = create_program_objects(store.programs, store)\n\n const filtered_countries = apply_country_filter(\n countries_obj,\n this.state.country_filter\n )\n\n const {countries, programs}= apply_program_filter(\n programs_obj,\n filtered_countries,\n this.state.program_filter\n )\n\n this.setState({\n countries: countries_obj,\n programs: programs_obj,\n country_selections: Object.entries(store.countries).map(([_, country]) => ({value: country.id, label: country.name})),\n filtered_countries: countries,\n filtered_programs: programs,\n ordered_country_ids: store.ordered_country_ids,\n flattened_programs: flattened_listing(store.ordered_country_ids.filter(id => id in countries).map(id => countries[id]), programs),\n original_user_program_access: create_user_access(store.editing_target_data.access),\n user_program_access: create_user_access(store.editing_target_data.access)\n })\n }\n\n saveForm() {\n //marshal the data back into the format we received it\n //filtering out all !has_access\n const access = this.state.user_program_access\n this.props.onSave({\n countries: Object.entries(access.countries)\n .filter(([_, country]) => this.props.store.is_superuser)\n .filter(([_, country]) => country.has_access)\n .reduce((countries, [id, country]) => ({...countries, [id]: country}), {}),\n programs: Object.entries(access.programs)\n .filter(([_, program]) => program.has_access)\n .map(([_, program]) => program)\n })\n }\n\n resetForm() {\n this.setState({\n user_program_access: {\n countries: {...this.state.original_user_program_access.countries},\n programs: {...this.state.original_user_program_access.programs}\n }\n })\n\n }\n\n toggleProgramAccess(program_key) {\n const current_program_access = this.state.user_program_access.programs\n const updated_program_access = (() => {\n if(current_program_access[program_key]) {\n return {...current_program_access[program_key], has_access: !current_program_access[program_key].has_access}\n } else {\n //TODO: want to find a more resilient way to handle a compound key\n const [country, program] = program_key.split('_')\n return {country, program, role: 'low', has_access: true}\n }\n })()\n\n this.setState({\n user_program_access: {\n ...this.state.user_program_access,\n programs: {\n ...current_program_access,\n [program_key]: updated_program_access\n }\n }\n })\n }\n\n toggleAllProgramsForCountry(country_id) {\n const country = this.state.countries[country_id]\n\n const new_program_access = (() => {\n const country_has_all_checked = country_has_all_access(\n country,\n this.state.filtered_programs,\n this.state.user_program_access\n )\n\n if(country_has_all_checked) {\n //toggle all off\n return Array.from(country.programs).filter(program_id => {\n return !!this.state.filtered_programs[program_id]\n }).reduce((programs, program_id) => {\n const program_key = `${country.id}_${program_id}`\n const program = this.state.user_program_access.programs[program_key]\n if(program) {\n return {...programs, [program_key]: {...program, has_access: false}}\n } else {\n return programs\n }\n }, {})\n } else {\n //toggle all on\n return Array.from(country.programs).filter(program_id => {\n return !!this.state.filtered_programs[program_id]\n }).reduce((programs, program_id) => {\n const program_key = `${country.id}_${program_id}`\n const program = this.state.user_program_access.programs[program_key]\n if(program) {\n return {...programs, [program_key]: {...program, has_access: true}}\n } else {\n return {...programs, [program_key]: {program: program_id, country: country.id, role: 'low', has_access: true}}\n }\n }, {})\n }\n })()\n this.setState({\n user_program_access: {\n ...this.state.user_program_access,\n programs: {...this.state.user_program_access.programs, ...new_program_access}\n }\n })\n }\n\n changeCountryRole(country_id, new_val) {\n const country = {...this.state.user_program_access.countries[country_id]}\n const new_country_access = (() => {\n if(new_val != 'none') {\n return {...country, role: new_val, has_access: true}\n } else {\n return {...country, role: new_val, has_access: false}\n }\n })()\n\n this.setState({\n user_program_access: {\n ...this.state.user_program_access,\n countries: {\n ...this.state.user_program_access.countries,\n [country_id]: new_country_access\n }\n },\n })\n }\n\n changeProgramRole(program_key, new_val) {\n const [country_id, program_id] = program_key.split('_')\n const access = this.state.user_program_access\n\n\n const new_program_access = (() => {\n if(access[country_id] && access[country_id].has_access && new_val == 'low') {\n return {\n program: program_id,\n country: country_id,\n role: new_val,\n has_access: false\n }\n } else {\n return {\n program: program_id,\n country: country_id,\n role: new_val,\n has_access: true\n }\n }\n })()\n\n this.setState({\n user_program_access: {\n ...this.state.user_program_access,\n programs: {\n ...this.state.user_program_access.programs,\n [program_key]: new_program_access\n }\n }\n })\n }\n\n clearFilter() {\n const val = ''\n const filtered_countries = apply_country_filter(this.state.countries, this.state.country_filter)\n const {countries, programs} = apply_program_filter(\n this.state.programs,\n filtered_countries,\n val\n )\n\n this.setState({\n program_filter: val,\n filtered_programs: programs,\n filtered_countries: countries,\n flattened_programs: flattened_listing(this.state.ordered_country_ids.filter(id => id in countries).map(id => countries[id]), programs),\n })\n }\n\n updateProgramFilter(val) {\n const filtered_countries = apply_country_filter(this.state.countries, this.state.country_filter)\n const {countries, programs} = apply_program_filter(\n this.state.programs,\n filtered_countries,\n val\n )\n\n this.setState({\n program_filter: val,\n filtered_programs: programs,\n filtered_countries: countries,\n flattened_programs: flattened_listing(this.state.ordered_country_ids.filter(id => id in countries).map(id => countries[id]), programs),\n })\n }\n\n changeCountryFilter(e) {\n const filtered_countries = apply_country_filter(this.state.countries, e)\n const {countries, programs} = apply_program_filter(\n this.state.programs,\n filtered_countries,\n this.state.program_filter\n )\n\n this.setState({\n country_filter: e,\n filtered_countries: countries,\n flattened_programs: flattened_listing(this.state.ordered_country_ids.filter(id => id in countries).map(id => countries[id]), this.state.filtered_programs),\n })\n }\n\n render() {\n const {user, onSave} = this.props\n\n const is_checked = (data) => {\n const access = this.state.user_program_access\n if(data.type == 'country') {\n return (access.countries[data.id] && access.countries[data.id].has_access) || false\n } else {\n if(this.state.user_program_access.countries[data.country_id] && this.state.user_program_access.countries[data.country_id].has_access) {\n return true\n }\n return (access.programs[data.id] && access.programs[data.id].has_access) || false\n }\n }\n\n const is_check_disabled = (data) => {\n if(data.type == 'country') {\n return !(this.state.countries[data.id].programs.size > 0)\n || !(\n this.props.store.access.countries[data.id]\n && this.props.store.access.countries[data.id].role == 'basic_admin'\n )\n || (\n this.state.user_program_access.countries[data.id]\n && this.state.user_program_access.countries[data.id].has_access\n )\n\n } else {\n if(this.state.user_program_access.countries[data.country_id] && this.state.user_program_access.countries[data.country_id].has_access) {\n return true\n }\n return !this.props.store.access.countries[data.country_id] || this.props.store.access.countries[data.country_id].role != 'basic_admin'\n }\n }\n\n const is_role_disabled = (data) => {\n if(data.type == 'country') {\n return !this.props.store.is_superuser\n } else {\n return (\n !this.props.store.access.countries[data.country_id]\n || this.props.store.access.countries[data.country_id].role != 'basic_admin'\n || (\n !(\n this.state.user_program_access.programs[data.id]\n && this.state.user_program_access.programs[data.id].has_access\n ) && !(\n this.state.user_program_access.countries[data.country_id]\n && this.state.user_program_access.countries[data.country_id].has_access\n )\n )\n )\n }\n }\n\n const get_role = (data) => {\n if(data.type == 'country') {\n const country_access = this.state.user_program_access.countries\n if(!country_access[data.id]) {\n return 'none'\n } else {\n return country_access[data.id].role\n }\n } else {\n const program_access = this.state.user_program_access.programs\n if(!program_access[data.id]) {\n return this.props.store.program_role_choices[0].value\n } else {\n return program_access[data.id].role\n }\n }\n }\n\n return (\n \n
{user.name?user.name+': ':''}{gettext(\"Programs and Roles\")} \n\n
\n
\n this.changeCountryFilter(e)} />\n
\n
\n
\n
this.updateProgramFilter(e.target.value)} />\n
\n
\n
\n
\n\n
\n
\n {({height, width}) =>\n this.state.flattened_programs[index]}\n rowHeight={50}\n rowCount={this.state.flattened_programs.length}>\n\n ({\n checked: is_checked(rowData),\n disabled: is_check_disabled(rowData),\n id: rowData.id,\n type: rowData.type,\n action: (rowData.type == \"country\")?this.toggleAllProgramsForCountry.bind(this):this.toggleProgramAccess.bind(this)\n })}\n cellRenderer={({cellData}) => {\n if (cellData.type == 'country') {\n const country_has_all_checked = country_has_all_access(\n this.state.countries[cellData.id],\n this.state.filtered_programs,\n this.state.user_program_access\n )\n const button_label = (country_has_all_checked)?gettext('Deselect All'):gettext('Select All')\n if(cellData.disabled) {\n return null\n } else {\n return \n }\n } else {\n return cellData.action(cellData.id)} />
\n }\n }}/>\n\n ({bold: rowData.type == \"country\", name: rowData.name})}\n cellRenderer={({cellData}) => {\n if(cellData.bold) {\n return {cellData.name} \n } else {\n return {cellData.name} \n }\n }} />\n\n ({\n id: rowData.id,\n disabled: is_role_disabled(rowData),\n type: rowData.type,\n options: rowData.options,\n action: (rowData.type == \"country\")?this.changeCountryRole.bind(this):this.changeProgramRole.bind(this)\n })}\n cellRenderer={({cellData}) =>\n cellData.action(cellData.id, e.target.value)}>\n {cellData.options.map(option => {option.label} )}\n \n }/>\n\n
\n }\n \n
\n\n
\n this.saveForm()}>Save Changes \n this.resetForm()}>Reset \n
\n\n
\n )\n }\n}\n","import React from 'react'\nimport {List, AutoSizer, CellMeasurer, CellMeasurerCache} from 'react-virtualized'\nimport Select, {components} from 'react-select'\n\nexport class VirtualizedMenuList extends React.PureComponent {\n constructor(props) {\n super(props)\n this.cache = new CellMeasurerCache({\n fixedWidth: true,\n defaultHeight: 35,\n })\n this.filter_val = \"\"\n }\n\n render() {\n const {options, children, maxHeight, getValue, selectProps} = this.props\n const rowCount = children.length || 0\n\n //gotta be a way to improve this. it's ok after the first couple of\n //characters search, but it's slow prior to that\n if(selectProps.inputValue !== this.filter_val) {\n this.filter_val = selectProps.inputValue\n this.cache.clearAll()\n }\n\n return (\n \n
\n
\n {({width, height}) => {\n return No selections available
}\n rowRenderer={\n ({index, parent, key, style}) =>\n \n {children[index]}
\n \n }/>\n }}\n
\n
\n
\n )\n }\n}\n\nconst VirtualizedSelect = props => (\n \n)\n\nexport default VirtualizedSelect\n","import React from 'react'\nimport Select from 'react-select'\nimport { observer } from \"mobx-react\"\n\n@observer\nexport default class EditUserProfile extends React.Component {\n constructor(props) {\n super(props)\n const {userData} = props\n const organization_listing = (() => {\n if(props.new) {\n return props.organizations.filter(o => o.value != 1 || props.is_superuser)\n } else {\n return props.organizations\n }\n })()\n const selected_organization = organization_listing.find(o => o.value == userData.organization_id)\n this.state = {\n original_user_data: {...userData},\n managed_user_data: {...userData},\n selected_organization,\n organization_listing\n }\n }\n\n\n save(e) {\n e.preventDefault()\n this.props.onUpdate(this.state.managed_user_data)\n }\n\n saveNew(e) {\n e.preventDefault()\n this.props.onCreate(this.state.managed_user_data)\n }\n\n saveNewAndAddAnother(e) {\n e.preventDefault()\n this.props.onCreateAndAddAnother(this.state.managed_user_data)\n }\n\n updateFirstName(new_first_name) {\n this.setState({\n managed_user_data: {\n ...this.state.managed_user_data,\n first_name: new_first_name,\n }\n })\n }\n\n updateLastName(new_last_name) {\n this.setState({\n managed_user_data: {\n ...this.state.managed_user_data,\n last_name: new_last_name,\n }\n })\n }\n\n updateOrganization(new_option) {\n this.setState({\n managed_user_data: {\n ...this.state.managed_user_data,\n organization_id: new_option.value,\n },\n selected_organization: new_option\n })\n }\n\n updateTitle(new_title) {\n this.setState({\n managed_user_data: {\n ...this.state.managed_user_data,\n title: new_title,\n }\n })\n }\n\n updateEmail(new_email) {\n this.setState({\n managed_user_data: {\n ...this.state.managed_user_data,\n email: new_email,\n }\n })\n }\n\n updatePhone(new_phone) {\n this.setState({\n managed_user_data: {\n ...this.state.managed_user_data,\n phone: new_phone,\n }\n })\n }\n\n updateModeOfContact(new_mode_of_contact) {\n this.setState({\n managed_user_data: {\n ...this.state.managed_user_data,\n mode_of_contact: new_mode_of_contact,\n }\n })\n }\n\n resetForm() {\n const selected_organization = this.state.organization_listing.find(o => o.value == this.state.original_user_data.organization_id)\n this.setState({\n managed_user_data: this.state.original_user_data,\n selected_organization\n })\n }\n\n render() {\n const ud = this.state.managed_user_data\n const e = this.props.errors\n const disabled = this.props.disabled\n const error_classes = {\n first_name: (e.first_name)?'is-invalid':'',\n last_name: (e.last_name)?'is-invalid':'',\n email: (e.email)?'is-invalid':'',\n organization: (e.organization_id)?'is-invalid':''\n }\n return (\n \n
{ud.name? ud.name+': ':''}Profile \n
\n \n
{gettext(\"Preferred First Name\")}* \n
this.updateFirstName(e.target.value) }\n id=\"user-first-name-input\"\n required />\n {e.first_name &&\n
\n {e.first_name}\n
\n }\n
\n \n
{gettext(\"Preferred Last Name\")}* \n
this.updateLastName(e.target.value) }\n id=\"user-last-name-input\"\n required />\n {e.last_name &&\n
\n {e.last_name}\n
\n }\n
\n \n
{gettext(\"Organization\")}* \n
this.updateOrganization(e)}\n placeholder=\"None Selected\"\n id=\"user-organization-input\" />\n {e.organization_id &&\n \n {e.organization_id}\n
\n }\n \n \n {gettext(\"Title\")} \n this.updateTitle(e.target.value)}\n className=\"form-control\"\n id=\"user-title-input\" />\n
\n \n
{gettext(\"Email\")}* \n
this.updateEmail(e.target.value)}\n id=\"user-email-input\" />\n {e.email &&\n
\n {e.email}\n
\n }\n
\n \n {gettext(\"Phone\")} \n this.updatePhone(e.target.value)}\n className=\"form-control\"\n id=\"user-phone-input\" />\n
\n \n {gettext(\"Preferred Mode of Contact\")} \n this.updateModeOfContact(e.target.value)}\n className=\"form-control\"\n id=\"user-mode-of-contact-input\" />\n
\n {this.props.new && !disabled &&\n \n this.saveNew(e)}>{gettext(\"Save changes\")} \n this.saveNewAndAddAnother(e)}>{gettext(\"Save And Add Another\")} \n this.resetForm()}>{gettext(\"Reset\")} \n
\n }\n {!this.props.new && !disabled &&\n \n this.save(e)}>{gettext(\"Save changes\")} \n this.resetForm()}>{gettext(\"Reset\")} \n
\n }\n \n
\n )\n }\n}\n","import React from 'react';\nimport ReactDOM from 'react-dom';\nimport {UserStore} from './models';\nimport {IndexView} from './views';\n\n/*\n * Model/Store setup\n */\nconst store = new UserStore(jsContext);\n\nReactDOM.render(\n ,\n document.querySelector('#app_root')\n);\n","\nimport React from 'react'\n\nconst LoadingSpinner = ({children, isLoading, className, ...props}) => {\n const loading = (isLoading)?'loading':''\n return \n}\n\nexport default LoadingSpinner\n","import React from 'react'\nimport { observer } from \"mobx-react\"\nimport Select from 'react-select'\nimport {AutoSizer, Table, Column, CellMeasurer, CellMeasurerCache} from 'react-virtualized'\nimport ChangeLog from 'components/changelog'\n\nconst status_options = [\n {value: true, label: gettext('Active')},\n {value: false, label: gettext('Inactive')}\n]\n\n\nexport class EditUserHistory extends React.Component {\n\n constructor(props) {\n super(props)\n this.state = {\n original_user_data: {user: {is_active: props.userData.user.is_active}},\n user_data: {user: {is_active: props.userData.user.is_active}}\n }\n }\n\n onChange(new_value) {\n this.setState({\n user_data: {\n user: {is_active: new_value.value}\n }\n })\n }\n\n onResendRegistrationEmail() {\n this.props.onResendRegistrationEmail()\n }\n\n onReset() {\n this.setState({\n user_data: this.state.original_user_data\n })\n }\n\n render() {\n const selected = status_options.find(option => option.value == this.state.user_data.user.is_active)\n const {history} = this.props\n return \n
{this.state.user_data.name?this.state.user_data.name+': ':''}{gettext(\"Status and History\")} \n
\n this.onChange(new_value)} />\n
\n
\n this.onResendRegistrationEmail()}>{gettext(\"Resend Registration Email\")} \n
\n {!this.props.disabled &&\n
\n
\n this.props.onSave(this.state.user_data)}>{gettext(\"Save Changes\")} \n this.onReset()}>{gettext(\"Reset\")} \n
\n
\n }\n
\n
\n }\n}\n\nexport default EditUserHistory\n","import React from 'react'\n\nconst ChangeField = ({name, data}) => {\n return \n {name} : {(data != undefined && data != null)?data.toString():'N/A'}\n
\n}\n\nconst ChangeLogEntryHeader = ({data}) => {\n return {/* TODO: apply is-expanded dynamically */}\n {data.date} \n {data.admin_user} \n {data.change_type} \n \n \n \n}\n\nconst ChangeLogEntryRow = ({data}) => {\n if (data.change_type == 'user_programs_updated') {\n // Create multiple row for program/country changes:\n return \n {Object.entries(data.diff_list.countries).length > 0 &&\n Object.entries(data.diff_list.countries).map(([id, country]) =>\n \n \n \n \n \n \n \n \n
\n \n \n \n \n \n
\n \n \n )\n }\n {Object.entries(data.diff_list.programs).length > 0 &&\n Object.entries(data.diff_list.programs).map(([id, program]) =>\n \n \n \n \n \n \n \n \n \n
\n \n \n \n \n \n \n
\n \n \n )\n }\n \n } else {\n return \n \n \n \n \n \n {data.diff_list.map((changeset, id) =>\n \n )}\n
\n \n \n \n {data.diff_list.map((changeset, id) =>\n \n )}\n
\n \n \n }\n}\n\nconst ChangeLogEntry = ({data}) => {\n return \n \n \n \n}\n\nconst ChangeLog = ({data}) => {\n return \n \n \n {gettext(\"Date\")} \n {gettext(\"Admin\")} \n {gettext(\"Change Type\")} \n {gettext(\"Previous Entry\")} \n {gettext(\"New Entry\")} \n \n \n {data.map((entry, id) =>\n \n )}\n
\n}\n\nexport default ChangeLog\n","import {api} from '../../../api';\n\nexport const fetchUsersWithFilter = (page, filters) => api.get('/tola_management/user/', {params: {page: page, ...filters}}).then(response => {\n let data = response.data\n\n let total_results_count = data.count\n let current_results_count = data.results.length\n let total_pages = data.page_count\n\n return {\n users: data.results,\n total_pages: total_pages,\n total_users: total_results_count,\n next_page: data.next,\n prev_page: data.previous\n }\n})\n\nexport const fetchUser = (user_id) => api.get(`/tola_management/user/${user_id}/`).then(response => response.data)\n\nexport const saveUserProfile = (user_id, data) => api.put(`/tola_management/user/${user_id}/`, data).then((response) => {\n return response.data\n})\n\nexport const updateUserIsActive = (user_id, data) => api.put(`/tola_management/user/${user_id}/is_active/`, data).then(response => response.data)\n\nexport const fetchUserProgramAccess = (user_id) => api.get(`/tola_management/user/${user_id}/program_access/`).then(response => response.data)\n\nexport const saveUserPrograms = (user_id, data) => api.put(`/tola_management/user/${user_id}/program_access/`, data).then(response => {\n\n})\n\nexport const fetchUserHistory = (user_id) => api.get(`/tola_management/user/${user_id}/history/`).then(response => response.data)\n\nexport const createUser = (new_user_data) => api.post(`/tola_management/user/`, new_user_data).then(response => {\n return response.data\n})\n\nexport const resendRegistrationEmail = (user_id) => api.post(`/tola_management/user/${user_id}/resend_registration_email/`, {}).then(response => response.data)\n\nexport const bulkUpdateUserStatus = (user_ids, new_status) => api.post(`/tola_management/user/bulk_update_status/`, {user_ids, new_status}).then(response => response.data)\nexport const bulkAddPrograms = (user_ids, added_programs) => api.post(`/tola_management/user/bulk_add_programs/`, {user_ids, added_programs}).then(response => response.data)\nexport const bulkRemovePrograms = (user_ids, removed_programs) => api.post(`/tola_management/user/bulk_remove_programs/`, {user_ids, removed_programs}).then(response => response.data)\n\nexport const fetchUserAggregates = (user_id) => api.get(`/tola_management/user/${user_id}/aggregate_data/`).then(response => response.data)\n\nexport default {\n fetchUsersWithFilter,\n fetchUser,\n saveUserProfile,\n fetchUserProgramAccess,\n saveUserPrograms,\n fetchUserHistory,\n createUser,\n resendRegistrationEmail,\n bulkUpdateUserStatus,\n bulkAddPrograms,\n bulkRemovePrograms,\n fetchUserAggregates,\n updateUserIsActive\n}\n","import React from 'react'\nimport ReactPaginate from 'react-paginate'\nimport { observer } from \"mobx-react\"\n\n/***\n Props:\n\n - pageCount: total number of pages\n - initialPage: which page should be highlighted as active initially\n - onPageChange: a function to receive the newly selected page\n*/\nconst Pagination = (props) => {\n return \n}\n\nexport default Pagination\n","import { observer } from \"mobx-react\"\nimport React from 'react';\nimport classNames from 'classnames';\n\n// TODO: \"size\" is no longer used\nconst ColumnComponent = ({className, size, ...props}) => {props.children} \n\n// TODO: this is redundant with ColumnComponent\nconst HeaderColumnComponent = ({className, size, ...props}) => {props.children} \n\nconst InnerRowComponent = ({className, ...props}) => {props.children} \n\n// TODO: this is redundant with InnerRowComponent\nconst HeaderRowComponent = ({className, ...props}) => {props.children} \n\n/***\n A wrapper for the rendering of the given row renderer, it takes and expando\n renderer used to render expanded content\n\n Props:\n - expanded: whether the expando content is shown or not\n - Expando: The content to render when the expando is shown\n*/\nconst RowComponent = observer(({className, expanded, Expando, ...props}) => {\n if(Expando) {\n const ObservedExpando = observer(Expando)\n return \n {props.children} \n {expanded && }\n \n } else {\n return \n {props.children} \n \n }\n})\nconst ExpandoWrapper = ({className, ...props}) => {props.children} \n\nconst RowList = observer(({data, Row, keyField, ...props}) => {\n const ObservedRow = observer(Row)\n return data.map(row_data => )\n})\n\n/*\n Props:\n\n - HeaderRow: a function to render the header row. it receives a component\n prop to render the header column and row\n\n - Row: a function used to render each row. it receives a component prop to\n render the row (see RowComponent), it receives the relevant data for that\n row as a prop: data\n\n - data: the dataset used to render the table, it must be an array\n\n - keyField: field to use for key on rows and expando checking\n\n */\nconst ManagementTable = observer(({HeaderRow, className, ...props}) => {\n const ObservedHeaderRow = observer(HeaderRow)\n return \n})\nexport default ManagementTable\n","import axios from 'axios';\n\nexport const api = axios.create({\n withCredentials: true,\n baseURL: '/api/',\n headers: {\n \"X-CSRFToken\": document.cookie.replace(/(?:(?:^|.*;\\s*)csrftoken\\s*\\=\\s*([^;]*).*$)|^.*$/, \"$1\")\n }\n});\n","import React from 'react'\nimport Select, {components} from 'react-select'\nimport {VirtualizedMenuList as MenuList} from './virtualized-react-select'\nimport {observer} from 'mobx-react'\n\nconst Option = props => {\n return (components.Option &&\n \n {\n //we can let the outer component manage state\n }}\n />\n \n {props.data.label}\n \n )\n}\n\nconst CheckboxedMultiSelect = observer(props => (\n \n))\n\nexport default CheckboxedMultiSelect\n","import React from 'react'\nimport { observer } from \"mobx-react\"\nimport Select from 'react-select'\nimport CheckboxedMultiSelect from 'components/checkboxed-multi-select'\nimport ManagementTable from 'components/management-table'\nimport UserEditor from './components/user_editor'\nimport EditUserProfile from './components/edit_user_profile'\nimport EditUserPrograms from './components/edit_user_programs'\nimport EditUserHistory from './components/edit_user_history'\nimport Pagination from 'components/pagination'\nimport LoadingSpinner from 'components/loading-spinner'\nimport FoldingSidebar from 'components/folding-sidebar'\n\nconst selection_placeholder = gettext(\"None Selected\")\nconst UserFilter = observer(({store, selections}) => {\n return \n {gettext(\"Users\")} \n store.changeUserFilter(e)}\n placeholder={selection_placeholder}\n id=\"users_filter\" />\n
\n})\n\nconst CountryFilter = observer(({store, selections}) => {\n return \n {gettext(\"Countries Permitted\")} \n store.changeCountryFilter(e)}\n placeholder={selection_placeholder}\n id=\"countries_permitted_filter\" />\n
\n})\n\nconst BaseCountryFilter = observer(({store, selections}) => {\n return \n {gettext(\"Base Country\")} \n store.changeBaseCountryFilter(e)}\n placeholder={selection_placeholder}\n id=\"base_country_filter\" />\n
\n})\n\nconst ProgramFilter = observer(({store, selections}) => {\n return \n {gettext(\"Programs\")} \n store.changeProgramFilter(e)}\n placeholder={selection_placeholder}\n id=\"programs_filter\" />\n
\n})\n\nclass SetUserStatusBulkAction extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n value: []\n }\n }\n\n onChange(new_val) {\n this.setState({\n value: new_val\n })\n }\n\n onApply() {\n this.props.onApply(this.state.value)\n }\n\n render() {\n return this.onChange(val)} />\n }\n}\n\nclass UpdateProgramsBulkAction extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n values: []\n }\n }\n\n onChange(new_vals) {\n this.setState({\n values: new_vals\n })\n }\n\n render() {\n return this.onChange(val)} />\n }\n}\n\nclass BulkActions extends React.Component {\n constructor(props) {\n super(props)\n this.active_child = React.createRef()\n this.state = {\n current_action: null,\n current_vals: []\n }\n }\n\n onActionChanged(new_action) {\n this.setState({\n current_action: new_action.value,\n current_vals: [],\n })\n }\n\n onChange(vals) {\n this.setState({\n current_vals: vals\n })\n }\n\n onApply() {\n const selected = this.props.secondaryOptions[this.state.current_action]\n if(selected) {\n selected.onApply(this.state.current_vals)\n }\n }\n\n render() {\n const selected = this.props.secondaryOptions[this.state.current_action]\n const SecondaryComponent = selected && selected.component\n const apply_disabled = !this.state.current_action || (Array.isArray(this.state.current_vals) && !this.state.current_vals.length) || !this.state.current_vals\n return \n
\n o.value == this.state.current_action)}\n options={this.props.primaryOptions} onChange={(val) => this.onActionChanged(val)} />\n
\n {selected &&\n
\n this.onChange(vals)}/>\n
\n }\n {!selected &&\n
\n \n
\n }\n
this.onApply()}>Apply \n
\n }\n}\n\nexport const IndexView = observer(\n ({store}) => {\n const programOptions = store.program_selections\n const bulk_actions = {\n primary_options: [\n {label: gettext('Set account status'), value: 'set_account_status'},\n {label: gettext('Add to program'), value: 'add_to_program'},\n {label: gettext('Remove from program'), value: 'remove_from_program'},\n ],\n secondary_options: {\n set_account_status: {\n component: (props) => ,\n onApply: (option) => store.bulkUpdateUserStatus(option.value)\n },\n add_to_program: {\n component: (props) => ,\n onApply: (vals) => store.bulkAddPrograms(vals.map(option => option.value))\n },\n remove_from_program: {\n component: (props) => ,\n onApply: (vals) => store.bulkRemovePrograms(vals.map(option => option.value))\n },\n }\n }\n\n return \n
\n \n
\n
\n
\n
\n {gettext(\"Organization\")} \n store.changeOrganizationFilter(e)}\n isMulti={true}\n placeholder={selection_placeholder}\n id=\"organization_filter\" />\n
\n
\n {gettext(\"Status\")} \n store.changeUserStatusFilter(e)}\n placeholder={selection_placeholder}\n id=\"status_filter\" />\n
\n
\n {gettext(\"Admin Role\")} \n store.changeAdminRoleFilter(e)}\n placeholder={selection_placeholder}\n id=\"admin_role_filter\" />\n
\n
\n
\n store.applyFilters()}>{gettext(\"Apply\")} \n store.clearFilters()}>{gettext(\"Reset\")} \n
\n
\n \n
\n
\n
\n \n \n
\n
{store.users_count?`${store.users_count} ${gettext(\"users\")}`:`--`}
\n
\n {store.total_pages &&\n
store.changePage(page)} />\n }\n \n
\n
\n
\n }\n)\n","import { observable, computed, action, runInAction } from \"mobx\";\nimport api from './api';\n\nconst default_user = {\n id: null,\n first_name: \"\",\n last_name: \"\",\n email: \"\",\n phone_number: \"\",\n organization_id: null,\n mode_of_contact: \"\",\n title: \"\",\n user_programs: 0,\n user: {is_active:true},\n}\n\nconst default_editing_target_data = {\n profile: {...default_user},\n access: {country: {}, programs:[]},\n history: []\n}\n\nexport class UserStore {\n @observable users = {}\n @observable users_listing = []\n @observable users_count = null\n @observable fetching_users_listing = false\n @observable current_page = 0\n @observable total_pages = null\n @observable bulk_targets = new Map()\n @observable bulk_targets_all = false\n @observable applying_bulk_updates = false\n\n @observable saving_user_profile = false\n @observable saving_user_programs = false\n\n @observable access = {countries: {}, programs: {}}\n @observable is_superuser = false\n\n @observable fetching_editing_target = false\n @observable editing_target = null\n @observable editing_target_data = {...default_editing_target_data}\n @observable editing_errors = {}\n\n @observable new_user = null\n\n //filter options\n @observable countries = {}\n @observable ordered_country_ids = []\n @observable organizations = {}\n @observable programs = {}\n @observable available_users = []\n\n @observable countries_selections = []\n @observable organization_selections = []\n @observable program_selections = []\n @observable user_selections = []\n @observable program_bulk_selections = []\n\n country_role_choices = []\n program_role_choices = []\n\n user_status_options = [\n {value: 1, label: 'Active'},\n {value: 0, label: 'Inactive'}\n ]\n\n admin_role_options = [\n {value: 1, label: 'Yes'},\n {value: 0, label: 'No'}\n ]\n\n @observable filters = {\n countries: [],\n base_countries: [],\n organizations: [],\n programs: [],\n user_status: '',\n admin_role: '',\n users: []\n }\n\n constructor({\n countries,\n organizations,\n programs,\n users,\n access,\n is_superuser,\n programs_filter,\n country_filter,\n organizations_filter,\n program_role_choices,\n country_role_choices,\n }) {\n this.countries = countries\n this.ordered_country_ids = Object.values(countries).sort((a, b) => a.name.localeCompare(b.name)).map(country => country.id)\n this.organizations = organizations\n this.programs = programs\n this.available_users = users.filter(user => user.name)\n\n this.countries_selections = this.ordered_country_ids.map(id => this.countries[id])\n .map(country => ({value: country.id, label: country.name}))\n\n this.organization_selections = Object.values(organizations).map(org => ({value: org.id, label: org.name}))\n\n this.program_selections = this.createProgramSelections(this.programs)\n\n this.user_selections = this.available_users.map(user => ({value: user.id, label: user.name}))\n\n this.program_bulk_selections = this.ordered_country_ids.map(id => this.countries[id]).map((country) => ({\n label: country.name,\n options: country.programs.map(program_id => ({\n label: country.name+\": \"+programs[program_id].name,\n value: country.id+\"_\"+program_id\n }))\n }))\n\n this.access = access\n this.is_superuser = is_superuser\n this.filters.programs = programs_filter.map(id => this.programs[id]).map(program => ({label: program.name, value: program.id}))\n this.filters.organizations = organizations_filter.map(id => this.organizations[id]).map(org => ({label: org.name, value: org.id}))\n this.filters.countries = country_filter.map(id => this.countries[id]).map(country => ({label: country.name, value: country.id}))\n\n this.country_role_choices = country_role_choices.map(([value, label]) => ({label, value}))\n this.program_role_choices = program_role_choices.map(([value, label]) => ({label, value}))\n this.fetchUsers()\n }\n\n /*******************\n we turn the complex intermediate filter objects into simple lists for\n transmission to the api, (while retaining their filter keys)\n\n eg\n\n {\n ...\n countries: [{label: 'Afghanistan', value: 1}]\n }\n\n becomes\n\n {\n ...\n countries: [1]\n }\n\n */\n marshalFilters(filters) {\n return Object.entries(filters).reduce((xs, x) => {\n if(Array.isArray(x[1])) {\n xs[x[0]] = x[1].map(x => x.value)\n } else {\n xs[x[0]] = x[1].value\n }\n return xs\n }, {})\n }\n\n getSelectedBulkTargetIDs() {\n return [...this.bulk_targets.entries()]\n .filter(([_, selected]) => selected)\n .map(([user_id, _]) => user_id)\n }\n\n onSaveErrorHandler(message) {\n PNotify.error({text: message || gettext('Saving Failed'), delay: 5000});\n }\n\n onSaveSuccessHandler(message) {\n PNotify.success({text: message || gettext('Successfully Saved'), delay: 5000})\n }\n\n createProgramSelections(programs) {\n return Object.values(programs).map(program => ({value: program.id, label: program.name}))\n }\n\n @action\n fetchUsers() {\n this.fetching_users_listing = true\n api.fetchUsersWithFilter(this.current_page + 1, this.marshalFilters(this.filters)).then(results => {\n runInAction(() => {\n this.fetching_users_listing = false\n this.users = results.users.reduce((xs, x) => {\n xs[x.id] = x\n return xs\n }, {})\n this.users_listing = results.users.map(u => u.id)\n this.bulk_targets_all = false\n this.bulk_targets = new Map()\n this.users_count = results.total_users\n this.total_pages = results.total_pages\n this.next_page = results.next_page\n this.previous_page = results.previous_page\n })\n })\n }\n\n @action\n applyFilters() {\n this.current_page = 0\n this.fetchUsers()\n }\n\n @action\n changePage(page) {\n if(page.selected != this.current_page) {\n this.current_page = page.selected\n this.fetchUsers()\n }\n }\n\n @action\n toggleBulkTargetsAll() {\n this.bulk_targets_all = !this.bulk_targets_all\n let user_ids = Object.values(this.users_listing)\n this.bulk_targets = new Map(user_ids.map(id => [id, this.bulk_targets_all]))\n }\n\n @action\n toggleBulkTarget(target_id) {\n this.bulk_targets.set(target_id, !this.bulk_targets.get(target_id))\n }\n\n @action\n changeCountryFilter(countries) {\n this.filters.countries = countries\n if(countries.length == 0) {\n this.program_selections = this.createProgramSelections(this.programs)\n } else {\n const candidate_programs = countries.map(selection => selection.value)\n .map(id => this.countries[id])\n .flatMap(country => country.programs)\n const selected_programs_set = new Set(candidate_programs)\n this.program_selections = this.createProgramSelections(Array.from(selected_programs_set).map(id => this.programs[id]))\n }\n }\n\n @action\n changeBaseCountryFilter(base_countries) {\n this.filters.base_countries = base_countries\n }\n\n @action\n changeOrganizationFilter(organizations) {\n this.filters.organizations = organizations\n }\n\n @action\n changeProgramFilter(programs) {\n this.filters.programs = programs\n }\n\n @action\n changeUserStatusFilter(status) {\n this.filters.user_status = status\n }\n\n @action\n changeAdminRoleFilter(role) {\n this.filters.admin_role = role\n }\n\n @action\n changeUserFilter(users) {\n this.filters.users = users\n }\n\n @action\n toggleEditingTarget(user_id) {\n this.editing_errors = {}\n this.editing_target_data = {...default_editing_target_data}\n if(this.editing_target == 'new') {\n this.users_listing.shift()\n }\n\n if(this.editing_target == user_id) {\n this.editing_target = null\n } else {\n this.editing_target = user_id\n this.fetching_editing_target = true\n Promise.all([api.fetchUser(user_id), api.fetchUserProgramAccess(user_id), api.fetchUserHistory(user_id)]).then(([user, access_data, history_data]) => {\n runInAction(() => {\n this.fetching_editing_target = false\n this.editing_target_data = {\n profile: user,\n access: access_data,\n history: history_data\n }\n })\n })\n }\n }\n\n @action\n updateActiveEditPage(section_name) {\n this.active_edit_page = section_name\n }\n\n @action\n createUser() {\n this.editing_errors = {}\n if(this.editing_target == 'new') {\n this.users_listing.shift()\n }\n\n this.editing_target_data = {...default_editing_target_data}\n\n this.users[\"new\"] = {\n id: \"new\",\n name: \"\",\n organization_name: \"\",\n user_programs: 0,\n is_admin: false,\n is_active: false\n }\n\n this.users_listing.unshift(\"new\")\n this.editing_target = 'new'\n }\n\n @action\n updateUserProfile(user_id, new_user_data) {\n this.saving_user_profile = true\n this.editing_errors = {}\n api.saveUserProfile(user_id, new_user_data).then(result => Promise.all([api.fetchUserAggregates(result.id), api.fetchUserHistory(result.id)]).then(([aggregates, history]) => {\n this.onSaveSuccessHandler()\n runInAction(() => {\n this.saving_user_profile = false\n this.users[result.id] = {\n id: result.id,\n name: result.name,\n organization_name: this.organizations[result.organization_id].name,\n user_programs: aggregates.program_count,\n is_admin: result.user.is_staff,\n is_active: result.user.is_active\n }\n this.editing_target_data.profile = result\n this.editing_target_data.history = history\n })\n })).catch(errors => {\n this.onSaveErrorHandler(errors.response.data.detail)\n runInAction(() => {\n this.saving_user_profile = false\n this.editing_errors = errors.response.data\n })\n })\n }\n\n @action\n updateUserIsActive(user_id, new_user_data) {\n this.saving_user_profile = true\n this.editing_errors = {}\n api.updateUserIsActive(user_id, new_user_data).then(result => Promise.all([api.fetchUserAggregates(user_id), api.fetchUserHistory(user_id)]).then(([aggregates, history]) => {\n this.onSaveSuccessHandler()\n runInAction(() => {\n this.saving_user_profile = false\n this.users[result.id] = {\n id: result.id,\n name: result.name,\n organization_name: this.organizations[result.organization_id].name,\n user_programs: aggregates.program_count,\n is_admin: result.user.is_staff,\n is_active: result.user.is_active\n }\n this.editing_target_data.profile = result\n this.editing_target_data.history = history\n })\n })).catch(errors => {\n this.onSaveErrorHandler(errors.response.data.detail)\n runInAction(() => {\n this.saving_user_profile = false\n this.editing_errors = errors.response.data\n })\n })\n }\n\n @action\n resendRegistrationEmail(user_id) {\n this.saving_user_profile = true\n api.resendRegistrationEmail(user_id).then(result => {\n runInAction(() => {\n this.saving_user_profile = false\n this.onSaveSuccessHandler(gettext(\"Verification email sent\"))\n })\n }).catch(() => {\n this.onSaveSuccessHandler(gettext(\"Verification email send failed\"))\n })\n }\n\n @action\n saveNewUser(new_user_data) {\n this.saving_user_profile = true\n this.editing_errors = {}\n api.createUser(new_user_data).then(result => api.fetchUserAggregates(result.id).then(aggregates => {\n this.onSaveSuccessHandler()\n runInAction(() => {\n this.saving_user_profile = false\n this.users[result.id] = {\n id: result.id,\n name: result.name,\n organization_name: this.organizations[result.organization_id].name,\n user_programs: aggregates.program_count,\n is_admin: result.user.is_staff,\n is_active: result.user.is_active\n }\n this.user_selections.push({value: result.id, label: result.name})\n this.users_listing[0] = result.id\n this.editing_target = null\n this.toggleEditingTarget(result.id)\n delete this.users[\"new\"]\n })\n })).catch(errors => {\n this.onSaveErrorHandler(errors.response.data.detail)\n runInAction(() => {\n this.saving_user_profile = false\n this.editing_errors = errors.response.data\n })\n })\n }\n\n @action\n saveNewUserAndAddAnother(new_user_data) {\n this.saving_user_profile = true\n this.editing_errors = {}\n api.createUser(new_user_data).then(result => api.fetchUserAggregates(result.id).then(aggregates => {\n this.onSaveSuccessHandler()\n runInAction(() => {\n this.saving_user_profile = false\n this.users[result.id] = {\n id: result.id,\n name: result.name,\n organization_name: this.organizations.find(o => o.id = result.organization_id).name,\n user_programs: aggregates.program_count,\n is_admin: result.user.is_staff,\n is_active: result.user.is_active\n }\n this.users_listing[0] = result.id\n delete this.users[\"new\"]\n this.createUser()\n })\n })).catch(errors => {\n this.onSaveErrorHandler(errors.response.data.detail)\n runInAction(() => {\n this.saving_user_profile = false\n this.editing_errors = errors.response.data\n })\n })\n }\n\n @action\n saveUserPrograms(user_id, new_user_programs_data) {\n this.saving_user_programs = true\n api.saveUserPrograms(user_id, new_user_programs_data).then(result => Promise.all([api.fetchUserAggregates(user_id), api.fetchUserHistory(user_id), api.fetchUserProgramAccess(user_id)]).then(([aggregates, history, access]) => {\n runInAction(() => {\n this.saving_user_programs = false\n this.users[user_id].user_programs = aggregates.program_count\n this.editing_target_data.history = history\n this.editing_target_data.access = access\n })\n this.onSaveSuccessHandler()\n })).catch(errors => {\n this.onSaveErrorHandler(errors.response.data.detail)\n runInAction(() => {\n this.saving_user_programs = false\n })\n })\n }\n\n @action\n bulkUpdateUserStatus(new_status) {\n this.applying_bulk_updates = true\n api.bulkUpdateUserStatus(\n this.getSelectedBulkTargetIDs(),\n new_status\n ).then(result => {\n runInAction(() => {\n result.forEach(updated => {\n let user = Object.assign(this.users[updated.id], updated)\n this.users[user.id] = user\n })\n this.applying_bulk_updates = false\n })\n this.onSaveSuccessHandler()\n }).catch(response => {\n runInAction(() => {\n this.applying_bulk_updates = false\n })\n this.onSaveErrorHandler()\n })\n }\n\n @action\n bulkAddPrograms(added_programs) {\n this.applying_bulk_updates = true\n api.bulkAddPrograms(\n this.getSelectedBulkTargetIDs(),\n added_programs.map(key => {\n const [country_id, program_id] = key.split('_')\n return {country: country_id, program: program_id, role: 'low'}\n })\n ).then(result => {\n //update open user programs\n const updated_users = this.getSelectedBulkTargetIDs()\n updated_users.forEach(id => {\n if(this.editing_target == id) {\n api.fetchUserProgramAccess(id).then(access => {\n runInAction(() => {\n this.editing_target_data.access = access\n })\n })\n }\n })\n\n runInAction(() => {\n Object.entries(result).forEach(([id, count]) => {\n this.users[id].user_programs = count\n })\n this.applying_bulk_updates = false\n })\n this.onSaveSuccessHandler()\n }).catch(response => {\n runInAction(() => {\n this.applying_bulk_updates = false\n })\n this.onSaveErrorHandler()\n })\n }\n\n @action\n bulkRemovePrograms(removed_programs) {\n this.applying_bulk_updates = true\n api.bulkRemovePrograms(\n this.getSelectedBulkTargetIDs(),\n removed_programs.map(key => {\n const [country_id, program_id] = key.split('_')\n return {country: country_id, program: program_id, role: 'low'}\n })\n ).then(result => {\n //update open user programs\n const updated_users = this.getSelectedBulkTargetIDs()\n updated_users.forEach(id => {\n if(this.editing_target == id) {\n api.fetchUserProgramAccess(id).then(access => {\n runInAction(() => {\n this.editing_target_data.access = access\n })\n })\n }\n })\n\n runInAction(() => {\n Object.entries(result).forEach(([id, count]) => {\n this.users[id].user_programs = count\n })\n this.applying_bulk_updates = false\n })\n\n this.onSaveSuccessHandler()\n }).catch(response => {\n runInAction(() => {\n this.applying_bulk_updates = false\n })\n this.onSaveErrorHandler()\n })\n }\n\n @action\n clearFilters() {\n this.filters = {\n countries: [],\n base_countries: [],\n organizations: [],\n programs: [],\n user_status: '',\n admin_role: '',\n users: []\n }\n }\n}\n","import React from 'react'\nimport { observer } from \"mobx-react\"\n\n@observer\nexport default class UserEditor extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n active_page: 'profile'\n }\n }\n\n updateActivePage(new_page) {\n if(!this.props.new) {\n this.setState({active_page: new_page})\n }\n }\n\n render() {\n const {ProfileSection, ProgramSection, HistorySection} = this.props\n\n const profile_active_class = (this.state.active_page == 'profile')?'active':''\n const programs_active_class = (this.state.active_page == 'programs_and_roles')?'active':''\n const history_active_class = (this.state.active_page == 'status_and_history')?'active':''\n const new_class = (this.props.new)?'disabled':''\n\n return (\n \n
\n
\n {this.state.active_page == 'profile' &&\n
\n }\n\n {this.state.active_page == 'programs_and_roles' &&\n
\n }\n\n {this.state.active_page == 'status_and_history' &&\n
\n }\n
\n
\n )\n }\n}\n","import React from 'react'\n\nclass Expander extends React.Component {\n constructor(props) {\n super(props)\n this.state = {\n folded: false,\n }\n }\n\n toggleFolded() {\n this.setState({\n folded: !this.state.folded\n })\n }\n\n render() {\n const {className, ...props} = this.props\n const icon = (this.state.folded)?\"fa-chevron-right\":\"fa-chevron-left\"\n return \n {!this.state.folded &&\n
{this.props.children} \n }\n\n
this.toggleFolded()}>\n \n
\n
\n }\n}\n\nexport default Expander\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AACA;AACA;AACA;AACA;AAEA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAIA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAPA;AAAA;AADA;AACA;AAWA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAIA;AACA;AALA;AAAA;AADA;AACA;AACA;AASA;AAAA;AAAA;AAIA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AALA;AAAA;AACA;AAQA;AACA;AACA;AACA;AACA;AAFA;AAIA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AAFA;AAIA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAFA;AAAA;AACA;AAIA;AAAA;AAEA;AAAA;AACA;AAAA;AAHA;AACA;AAQA;;;;;AACA;AAAA;AACA;AADA;AACA;AAAA;AADA;AAIA;AACA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AAXA;AAPA;AAoBA;AACA;;;AACA;AAAA;AAEA;AACA;AAEA;AACA;AANA;AAAA;AAAA;AACA;AAeA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AATA;AAWA;;;AAEA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AAAA;AAPA;AASA;;;AAEA;AACA;AACA;AACA;AACA;AAFA;AADA;AAOA;;;AAEA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AACA;AACA;AADA;AAAA;AAAA;AAAA;AACA;AAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAFA;AADA;AASA;;;AAEA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAEA;AAFA;AADA;AAMA;;;AAEA;AACA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AAFA;AADA;AASA;;;AAEA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AAJA;AAMA;AACA;AACA;AACA;AACA;AACA;AAJA;AAMA;AACA;AACA;AACA;AACA;AAEA;AAFA;AADA;AASA;;;AAEA;AACA;AACA;AACA;AAHA;AAAA;AAAA;AACA;AAQA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAJA;AAMA;;;AAEA;AACA;AACA;AAFA;AAAA;AAAA;AACA;AAOA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAJA;AAMA;;;AAEA;AACA;AACA;AAFA;AAAA;AAAA;AACA;AAOA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAHA;AAKA;;;AAEA;AAAA;AACA;AADA;AAAA;AAAA;AACA;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAUA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAaA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AACA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AADA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAOA;AAAA;AAEA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AANA;AASA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AALA;AAAA;AAOA;AAAA;AACA;AAAA;AACA;AAKA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AA1BA;AA6BA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAZA;AAeA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AALA;AAAA;AAOA;AAAA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAHA;AAIA;AAAA;AAAA;AAAA;AAAA;AALA;AAZA;AAnDA;AA6EA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA;;;;AA5aA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/EA;AACA;AACA;AAEA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AADA;AACA;AAAA;AACA;AACA;AACA;AAFA;AAIA;AANA;AAOA;AACA;AATA;AAAA;AAAA;AAUA;AACA;AADA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAGA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAFA;AARA;AAaA;AAKA;AA5CA;AACA;AADA;AAAA;AACA;AA8CA;AAAA;AAEA;AACA;AADA;AADA;AADA;AACA;AAOA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC3DA;AACA;AACA;AACA;AAEA;;;;;AACA;AAAA;AACA;AADA;AACA;AAAA;AADA;AACA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAJA;AAXA;AAiBA;AACA;;;AAEA;AACA;AACA;AACA;;;AAEA;AACA;AACA;AACA;;;AAEA;AACA;AACA;AACA;;;AAEA;AACA;AACA;AAEA;AAFA;AADA;AAMA;;;AAEA;AACA;AACA;AAEA;AAFA;AADA;AAMA;;;AAEA;AACA;AACA;AAEA;AAFA;AAIA;AALA;AAOA;;;AAEA;AACA;AACA;AAEA;AAFA;AADA;AAMA;;;AAEA;AACA;AACA;AAEA;AAFA;AADA;AAMA;;;AAEA;AACA;AACA;AAEA;AAFA;AADA;AAMA;;;AAEA;AACA;AACA;AAEA;AAFA;AADA;AAMA;;;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAFA;AAIA;;;AAEA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAJA;AAMA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAEA;AACA;AACA;AACA;AACA;AAAA;AAAA;A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AAHA;;;;;;;;;;;;;;;;;;;;ACFA;AACA;AACA;AACA;AACA;AACA;AACA;AAGA;AACA;AACA;AACA;AAEA;AANA;AAYA;AACA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAFA;AAJA;AADA;AAYA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AClCA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AALA;AAOA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AALA;AAOA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AALA;AAOA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AALA;AAOA;AACA;AACA;;;;;AACA;AAAA;AACA;AADA;AACA;AAAA;AACA;AACA;AADA;AAFA;AAKA;AACA;;;AACA;AACA;AACA;AADA;AAGA;;;AAEA;AACA;AACA;;;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;;;;AApBA;AACA;AAsBA;;;;;AACA;AAAA;AACA;AADA;AACA;AAAA;AACA;AACA;AADA;AAFA;AAKA;AACA;;;AACA;AACA;AACA;AADA;AAGA;;;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;;;;AAhBA;AACA;AAkBA;;;;;AACA;AAAA;AACA;AADA;AACA;AAAA;AACA;AACA;AACA;AACA;AAFA;AAHA;AAOA;AACA;;;AACA;AACA;AACA;AACA;AAFA;AAIA;;;AAEA;AACA;AACA;AADA;AAGA;;;AAEA;AACA;AACA;AAAA;AACA;AACA;AACA;;;AAEA;AAAA;AACA;AAAA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA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CA;AACA;AACA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAHA;AAKA;AACA;AACA;AACA;AA9QA;AAAA;AAAA;AAkRA;AACA;AAnRA;AAAA;AAAA;AAuRA;AACA;AAAA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AASA;AACA;AACA;AAzSA;AAAA;AAAA;AA4SA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAQA;AACA;AACA;AACA;AAfA;AAgBA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AArUA;AAAA;AAAA;AAwUA;AACA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AAQA;AACA;AACA;AACA;AAfA;AAgBA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAjWA;AAAA;AAAA;AAoWA;AACA;AAAA;AACA;AACA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AA9WA;AAAA;AAAA;AAiXA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AANA;AACA;AAOA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AACA;AAAA;AACA;AAAA;AACA;AACA;AAlBA;AAmBA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AA7YA;AAAA;AAAA;AAgZA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AACA;AACA;AANA;AAQA;AACA;AACA;AAAA;AACA;AACA;AAhBA;AAiBA;AACA;AAAA;AACA;AACA;AACA;AACA;AACA;AA1aA;AAAA;AAAA;AA6aA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;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","sourceRoot":""}
\ No newline at end of file
diff --git a/build/dist/audit_log-28b6b761e87ded230c20.js b/build/dist/audit_log-28b6b761e87ded230c20.js
deleted file mode 100644
index f48a6c8d..00000000
--- a/build/dist/audit_log-28b6b761e87ded230c20.js
+++ /dev/null
@@ -1 +0,0 @@
-(window.webpackJsonp=window.webpackJsonp||[]).push([[2],{"5Xg7":function(e,t,n){"use strict";n.d(t,"a",function(){return m});var a=n("q1tI"),l=n.n(a),c=n("c7k8"),r=n("y2Vs");function i(e){return(i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function o(){return(o=Object.assign||function(e){for(var t=1;tthis.ref.current.clientHeight&&this.setState({overflowing:!0})}},{key:"toggleExpanded",value:function(e){e.preventDefault(),this.setState({expanded:!this.state.expanded})}},{key:"render",value:function(){var t=this;return i.a.createElement("div",null,i.a.createElement("div",{ref:this.ref,className:"expander",style:{height:!this.state.expanded&&(this.props.height||50)}},this.props.children),this.state.overflowing&&i.a.createElement("div",null,i.a.createElement("a",{href:"",onClick:function(e){return t.toggleExpanded(e)}},this.state.expanded?"Show Less":"Show More")))}}])&&o(t.prototype,a),r&&o(t,r),n}();t.a=s},RCjz:function(e,t,n){"use strict";var a=n("q1tI"),r=n.n(a),i=n("werx"),o=n.n(i);n("okNM");function l(){return(l=Object.assign||function(e){for(var t=1;t td {
padding: 30px; }
-#user-management-index-view .edit-user-history table .program-changeset-row,
-#program-management-index-view .edit-user-history table .program-changeset-row,
-#country-management-index-view .edit-user-history table .program-changeset-row {
- border: 1px solid #aaa;
- padding: 5px; }
-
.edit-user-programs .check-column {
text-align: center; }
@@ -8399,9 +8396,12 @@ span[data-toggle="popover"]:hover {
cursor: pointer;
width: 40px; }
-.expander {
+.changelog-entry__expanding {
overflow: hidden; }
+.changelog__entry__header.is-expanded {
+ background-color: #ebedf0; }
+
/* Safari */
@-webkit-keyframes spin {
0% {
@@ -8459,8 +8459,6 @@ table.admin-list__table {
vertical-align: top; }
table.admin-list__table th, table.admin-list__table td {
vertical-align: top; }
- table.admin-list__table .expand-section {
- width: 10%; }
.objective-form-buttons {
display: flex; }
@@ -9201,5 +9199,3 @@ a:hover {
/* Unsorted custom selectors */
-
-/*# sourceMappingURL=base-a3666adfd3893f62c008.css.map*/
\ No newline at end of file
diff --git a/build/dist/base-7860ec9e0d43417984e1.js b/build/dist/base-84ad999e3b8337cb7619.js
similarity index 100%
rename from build/dist/base-7860ec9e0d43417984e1.js
rename to build/dist/base-84ad999e3b8337cb7619.js
diff --git a/build/dist/tola_management_organization-0c191946c56ef13da563.js b/build/dist/tola_management_organization-0c191946c56ef13da563.js
deleted file mode 100644
index 0d136e56..00000000
--- a/build/dist/tola_management_organization-0c191946c56ef13da563.js
+++ /dev/null
@@ -1 +0,0 @@
-(window.webpackJsonp=window.webpackJsonp||[]).push([[7],{"5Xg7":function(e,t,n){"use strict";n.d(t,"a",function(){return m});var a=n("q1tI"),c=n.n(a),l=n("c7k8"),r=n("y2Vs");function i(e){return(i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function o(){return(o=Object.assign||function(e){for(var t=1;tthis.ref.current.clientHeight&&this.setState({overflowing:!0})}},{key:"toggleExpanded",value:function(e){e.preventDefault(),this.setState({expanded:!this.state.expanded})}},{key:"render",value:function(){var t=this;return i.a.createElement("div",null,i.a.createElement("div",{ref:this.ref,className:"expander",style:{height:!this.state.expanded&&(this.props.height||50)}},this.props.children),this.state.overflowing&&i.a.createElement("div",null,i.a.createElement("a",{href:"",onClick:function(e){return t.toggleExpanded(e)}},this.state.expanded?"Show Less":"Show More")))}}])&&o(t.prototype,a),r&&o(t,r),n}();t.a=u},RCjz:function(e,t,n){"use strict";var a=n("q1tI"),r=n.n(a),i=n("werx"),o=n.n(i);n("okNM");function c(){return(c=Object.assign||function(e){for(var t=1;tthis.ref.current.clientHeight&&this.setState({overflowing:!0})}},{key:"toggleExpanded",value:function(e){e.preventDefault(),this.setState({expanded:!this.state.expanded})}},{key:"render",value:function(){var t=this;return o.a.createElement("div",null,o.a.createElement("div",{ref:this.ref,className:"expander",style:{height:!this.state.expanded&&(this.props.height||50)}},this.props.children),this.state.overflowing&&o.a.createElement("div",null,o.a.createElement("a",{href:"",onClick:function(e){return t.toggleExpanded(e)}},this.state.expanded?"Show Less":"Show More")))}}])&&i(t.prototype,n),a&&i(t,a),r}();t.a=u},RCjz:function(e,t,r){"use strict";var n=r("q1tI"),a=r.n(n),o=r("werx"),i=r.n(o);r("okNM");function l(){return(l=Object.assign||function(e){for(var t=1;tthis.ref.current.clientHeight&&this.setState({overflowing:!0})}},{key:"toggleExpanded",value:function(e){e.preventDefault(),this.setState({expanded:!this.state.expanded})}},{key:"render",value:function(){var t=this;return o.a.createElement("div",null,o.a.createElement("div",{ref:this.ref,className:"expander",style:{height:!this.state.expanded&&(this.props.height||50)}},this.props.children),this.state.overflowing&&o.a.createElement("div",null,o.a.createElement("a",{href:"",onClick:function(e){return t.toggleExpanded(e)}},this.state.expanded?"Show Less":"Show More")))}}])&&i(t.prototype,n),a&&i(t,a),r}();t.a=l},RCjz:function(e,t,r){"use strict";var n=r("q1tI"),a=r.n(n),o=r("werx"),i=r.n(o);r("okNM");function s(){return(s=Object.assign||function(e){for(var t=1;t 1 and value[-1] != '%' and value not in ['N/A', '—']:
+ if percent and len(value) > 1 and value[-1] != '%' and value not in ['N/A', 'N/A']:
value = value + '%'
cell.value = value
diff --git a/js/components/changelog.js b/js/components/changelog.js
new file mode 100644
index 00000000..e604b765
--- /dev/null
+++ b/js/components/changelog.js
@@ -0,0 +1,115 @@
+import React from 'react'
+
+const ChangeField = ({name, data}) => {
+ return
+ {name} : {(data != undefined && data != null)?data.toString():'N/A'}
+
+}
+
+const ChangeLogEntryHeader = ({data}) => {
+ return {/* TODO: apply is-expanded dynamically */}
+ {data.date}
+ {data.admin_user}
+ {data.change_type}
+
+
+
+}
+
+const ChangeLogEntryRow = ({data}) => {
+ if (data.change_type == 'user_programs_updated') {
+ // Create multiple row for program/country changes:
+ return
+ {Object.entries(data.diff_list.countries).length > 0 &&
+ Object.entries(data.diff_list.countries).map(([id, country]) =>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+ {Object.entries(data.diff_list.programs).length > 0 &&
+ Object.entries(data.diff_list.programs).map(([id, program]) =>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ )
+ }
+
+ } else {
+ return
+
+
+
+
+
+ {data.diff_list.map((changeset, id) =>
+
+ )}
+
+
+
+
+ {data.diff_list.map((changeset, id) =>
+
+ )}
+
+
+
+ }
+}
+
+const ChangeLogEntry = ({data}) => {
+ return
+
+
+
+}
+
+const ChangeLog = ({data}) => {
+ return
+
+
+ {gettext("Date")}
+ {gettext("Admin")}
+ {gettext("Change Type")}
+ {gettext("Previous Entry")}
+ {gettext("New Entry")}
+
+
+ {data.map((entry, id) =>
+
+ )}
+
+}
+
+export default ChangeLog
diff --git a/js/components/expander.js b/js/components/expander.js
index d281e296..320bfe39 100644
--- a/js/components/expander.js
+++ b/js/components/expander.js
@@ -24,12 +24,12 @@ class Expander extends React.Component {
}
render() {
- return
-
+ return
+
{this.props.children}
{this.state.overflowing &&
-
+
}
diff --git a/js/pages/tola_management_pages/audit_log/views.js b/js/pages/tola_management_pages/audit_log/views.js
index 30f3772c..55178058 100644
--- a/js/pages/tola_management_pages/audit_log/views.js
+++ b/js/pages/tola_management_pages/audit_log/views.js
@@ -11,9 +11,9 @@ import LoadingSpinner from 'components/loading-spinner'
const ResultChangeset = ({data, name, pretty_name}) => {
if(name == 'evidence_url') {
- return
{pretty_name}: {(data != 'N/A')?Link :data}
+ return
{pretty_name} : {(data != 'N/A')?
Link :data}
} else {
- return
{pretty_name}: {data}
+ return
{pretty_name} : {data}
}
}
@@ -23,16 +23,16 @@ const ProgramDatesChangeset = ({data, name, pretty_name}) => {
const IndicatorChangeset = ({data, name, pretty_name}) => {
if(name == 'targets') {
- return
-
Targets
+ return
+
{gettext('Targets changed')}
{Object.entries(data).map(([id, target]) => {
- return
{target.name}: {target.value}
+ return
{target.name}: {target.value}
})}
} else {
- return
- {pretty_name}: {(data !== null && data !== undefined)?data.toString():'N/A'}
-
+ return
+ {pretty_name}: {(mapped_data !== null && mapped_data !== undefined)?mapped_data.toString():'N/A'}
+
}
}
@@ -63,52 +63,66 @@ class ChangesetEntry extends React.Component {
export const IndexView = observer(
({store}) => {
- return
+ return
-
+
-
+
- {gettext("Date and Time")}
- {gettext("No.")}
- {gettext("Indicator")}
- {gettext("User")}
- {gettext("Organization")}
- {gettext("Change Type")}
- {gettext("Previous Entry")}
- {gettext("New Entry")}
- {gettext("Rationale")}
+ {gettext("Date and Time")}
+ {gettext("No.")}
+ {gettext("Indicator")}
+ {gettext("User")}
+ {gettext("Organization")}
+ {gettext("Change Type")}
+ {gettext("Previous Entry")}
+ {gettext("New Entry")}
+ {gettext("Rationale")}
-
- {store.log_rows.map(data =>
+ {store.log_rows.map(data =>
+
{data.date}
{(data.indicator)?data.indicator.number:'N/A'}
{(data.indicator)?data.indicator.name:'N/A'}
{data.user}
{data.organization}
- {data.pretty_change_type}
-
-
- {data.diff_list.map(changeset => {
- return
- })}
-
+ {data.pretty_change_type} {/* SWEET FANCY MOSES WHAT IS THIS */}
+
+
+
+
+
+
+
+
+
+
+
+
+ {data.diff_list.map(changeset => {
+ return
+ })}
-
-
- {data.diff_list.map(changeset => {
- return
- })}
-
+
+ {data.diff_list.map(changeset => {
+ return
+ })}
- {data.rationale}
- )}
+ {data.rationale}
+
+ )}
diff --git a/js/pages/tola_management_pages/organization/components/edit_organization_history.js b/js/pages/tola_management_pages/organization/components/edit_organization_history.js
index bab4057e..0926fb3d 100644
--- a/js/pages/tola_management_pages/organization/components/edit_organization_history.js
+++ b/js/pages/tola_management_pages/organization/components/edit_organization_history.js
@@ -3,16 +3,13 @@ import { observer } from "mobx-react"
import Select from 'react-select'
import {AutoSizer, Table, Column, CellMeasurer, CellMeasurerCache} from 'react-virtualized'
import Expander from 'components/expander'
+import ChangeLog from 'components/changelog'
const status_options = [
{value: true, label: gettext('Active')},
{value: false, label: gettext('Inactive')}
]
-const ChangesetEntry = ({name, type, data, pretty_name}) => {
- return
{pretty_name} : {(data != undefined && data != null)?data.toString():'N/A'}
-}
-
export default class EditOrganizationHistory extends React.Component {
constructor(props) {
@@ -100,6 +97,9 @@ export default class EditOrganizationHistory extends React.Component {
+
+
+
}
}
diff --git a/js/pages/tola_management_pages/program/components/program_history.js b/js/pages/tola_management_pages/program/components/program_history.js
index bf5e1297..515f5d3e 100755
--- a/js/pages/tola_management_pages/program/components/program_history.js
+++ b/js/pages/tola_management_pages/program/components/program_history.js
@@ -3,16 +3,13 @@ import Select from 'react-select'
import {AutoSizer, Table, Column, CellMeasurer, CellMeasurerCache} from 'react-virtualized'
import { observer } from 'mobx-react';
import Expander from 'components/expander'
+import ChangeLog from 'components/changelog'
const status_options = [
{value: 'Funded', label: 'Funded'},
{value: 'Completed', label: 'Completed'}
]
-const ChangesetEntry = ({name, type, data, pretty_name}) => {
- return
{pretty_name} : {(data != undefined && data != null)?data.toString():'N/A'}
-}
-
@observer
export class ProgramHistory extends React.Component {
@@ -102,6 +99,7 @@ export class ProgramHistory extends React.Component {
+
}
}
diff --git a/js/pages/tola_management_pages/user/components/edit_user_history.js b/js/pages/tola_management_pages/user/components/edit_user_history.js
index 4de29b75..5647d7d1 100755
--- a/js/pages/tola_management_pages/user/components/edit_user_history.js
+++ b/js/pages/tola_management_pages/user/components/edit_user_history.js
@@ -2,44 +2,13 @@ import React from 'react'
import { observer } from "mobx-react"
import Select from 'react-select'
import {AutoSizer, Table, Column, CellMeasurer, CellMeasurerCache} from 'react-virtualized'
-import Expander from 'components/expander'
+import ChangeLog from 'components/changelog'
const status_options = [
{value: true, label: gettext('Active')},
{value: false, label: gettext('Inactive')}
]
-const ChangesetEntry = ({name, type, data, pretty_name}) => {
- return
{pretty_name} : {(data != undefined && data != null)?data.toString():'N/A'}
-}
-
-const ProgramChangesetEntry = ({data, timeframe}) => {
- return
- {Object.entries(data.countries).length > 0 &&
-
-
Countries
- {Object.entries(data.countries).map(([id, country]) =>
-
-
{gettext("Country")} : {country[timeframe].country}
-
{gettext("Role")} : {country[timeframe].role}
-
- )}
-
- }
- {Object.entries(data.programs).length > 0 &&
-
-
Programs
- {Object.entries(data.programs).map(([id, program]) =>
-
-
{gettext("Program")} : {program[timeframe].program}
-
{gettext("Country")} : {program[timeframe].country}
-
{gettext("Role")} : {program[timeframe].role}
-
- )}
-
- }
-
-}
export class EditUserHistory extends React.Component {
@@ -92,65 +61,8 @@ export class EditUserHistory extends React.Component {
this.onReset()}>{gettext("Reset")}
- }
-
-
-
-
-
-
- {gettext("Date")}
- {gettext("Admin")}
- {gettext("Change Type")}
- {gettext("Previous Entry")}
- {gettext("New Entry")}
-
-
-
- {history.map(entry => {
- if(entry.change_type == 'user_programs_updated') {
- return
- {entry.date}
- {entry.admin_user}
- {entry.pretty_change_type}
-
-
-
-
-
-
-
-
-
-
-
- } else {
-
- return
- {entry.date}
- {entry.admin_user}
- {entry.pretty_change_type}
-
-
- {entry.diff_list.map(changeset => {
- return
- })}
-
-
-
-
- {entry.diff_list.map(changeset => {
- return
- })}
-
-
-
- }
- })}
-
-
-
-
+ }
+
}
}
diff --git a/js/pages/tola_management_pages/user/components/user_editor.js b/js/pages/tola_management_pages/user/components/user_editor.js
index af0d6b8b..2eb47e2c 100644
--- a/js/pages/tola_management_pages/user/components/user_editor.js
+++ b/js/pages/tola_management_pages/user/components/user_editor.js
@@ -34,13 +34,13 @@ export default class UserEditor extends React.Component {
- { e.preventDefault(); this.updateActivePage('programs_and_roles')}}>
{gettext("Programs and Roles")}
- { e.preventDefault(); this.updateActivePage('status_and_history')}}>
{gettext("Status and History")}
diff --git a/js/pages/tola_management_pages/user/views.js b/js/pages/tola_management_pages/user/views.js
index 408694db..617f1e4f 100644
--- a/js/pages/tola_management_pages/user/views.js
+++ b/js/pages/tola_management_pages/user/views.js
@@ -229,7 +229,7 @@ export const IndexView = observer(
diff --git a/scss/components/_tables.scss b/scss/components/_tables.scss
index a4bff23f..2e0aaaa5 100644
--- a/scss/components/_tables.scss
+++ b/scss/components/_tables.scss
@@ -16,3 +16,7 @@
// more semantic version of w-100
width: 100%;
}
+.td--half-stretch {
+ // more semantic version of w-50
+ width: 50%;
+}
diff --git a/scss/components/_tola_management.scss b/scss/components/_tola_management.scss
index 59ebe1e4..2a3b997a 100644
--- a/scss/components/_tola_management.scss
+++ b/scss/components/_tola_management.scss
@@ -2,10 +2,6 @@
#program-management-index-view,
#country-management-index-view {
.edit-user-history table {
- .program-changeset-row {
- border: 1px solid #aaa;
- padding: 5px;
- }
}
@@ -122,9 +118,44 @@
}
}
-.expander {
+// Expanding change logs
+// OLD SELECTORS, DELETE US!
+.changelog-entry {}
+.changelog-entry__expanding {
+ // expanding child element
overflow: hidden;
}
+.changelog-entry__expand-trigger {}
+
+// NEW SELECTORS
+.changelog { //
+}
+.changelog__entry { // each timestamped batch of DB updates;
+}
+.changelog__entry__header { // title row for changelog__entry;
+ &.is-expanded {
+ background-color: $gray-200;
+ }
+}
+.changelog__entry__row { // each DB row change;
+}
+.changelog__change {
+ // inside a row
+ // collects a group of changes made at the same time
+}
+.changelog__change--prev {
+ // previous values
+}
+.changelog__change--new {
+ // new values
+}
+.changelog__change--rationale {
+ // only on indicator report, ie. from IPTT
+}
+.changelog__change__targets {
+ // only on indicator report, ie. from IPTT
+ // group of targets inside the prev/new component
+}
/* Safari */
@-webkit-keyframes spin {
@@ -195,10 +226,6 @@ table.admin-list__table {
th, td {
vertical-align: top;
}
-
- .expand-section {
- width: 10%;
- }
}
.objective-form-buttons {
diff --git a/tola/settings/test.py b/tola/settings/test.py
index 2220b00c..b8ab87a3 100644
--- a/tola/settings/test.py
+++ b/tola/settings/test.py
@@ -25,8 +25,6 @@ def __getitem__(self, item):
"default": {
"ENGINE": "django.db.backends.mysql",
"NAME": "tola_activity",
- "USER": "mercy_corps",
- "PASSWORD": "mercy_corps",
"HOST": "localhost",
"PORT": "",
},
diff --git a/tola_management/programadmin.py b/tola_management/programadmin.py
index 9db11489..18e11ce0 100644
--- a/tola_management/programadmin.py
+++ b/tola_management/programadmin.py
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
import json
import csv
from StringIO import StringIO
diff --git a/webpack-stats-dev.json b/webpack-stats-dev.json
index b557b48c..8e681c80 100644
--- a/webpack-stats-dev.json
+++ b/webpack-stats-dev.json
@@ -1 +1 @@
-{"status":"done","chunks":{"audit_log":[{"name":"audit_log-8f3ec9b285211b3b3934.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/audit_log-8f3ec9b285211b3b3934.js"},{"name":"audit_log-8f3ec9b285211b3b3934.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/audit_log-8f3ec9b285211b3b3934.js.map"}],"base":[{"name":"base-a3666adfd3893f62c008.css","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/base-a3666adfd3893f62c008.css"},{"name":"base-fdebc32420e55b9873d8.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/base-fdebc32420e55b9873d8.js"},{"name":"base-a3666adfd3893f62c008.css.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/base-a3666adfd3893f62c008.css.map"},{"name":"base-fdebc32420e55b9873d8.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/base-fdebc32420e55b9873d8.js.map"}],"document_list":[{"name":"document_list-4bf5d1e03d38a6eaca94.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/document_list-4bf5d1e03d38a6eaca94.js"},{"name":"document_list-4bf5d1e03d38a6eaca94.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/document_list-4bf5d1e03d38a6eaca94.js.map"}],"program_page":[{"name":"program_page-fff173154048bae63e32.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/program_page-fff173154048bae63e32.js"},{"name":"program_page-fff173154048bae63e32.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/program_page-fff173154048bae63e32.js.map"}],"runtime":[{"name":"runtime-618bcded6741c4c27fdf.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/runtime-618bcded6741c4c27fdf.js"},{"name":"runtime-618bcded6741c4c27fdf.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/runtime-618bcded6741c4c27fdf.js.map"}],"tola_management_country":[{"name":"tola_management_country-d2d40a6be9de670de4c2.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/tola_management_country-d2d40a6be9de670de4c2.js"},{"name":"tola_management_country-d2d40a6be9de670de4c2.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/tola_management_country-d2d40a6be9de670de4c2.js.map"}],"tola_management_organization":[{"name":"tola_management_organization-4c0e78fa1302d9fc5d80.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/tola_management_organization-4c0e78fa1302d9fc5d80.js"},{"name":"tola_management_organization-4c0e78fa1302d9fc5d80.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/tola_management_organization-4c0e78fa1302d9fc5d80.js.map"}],"tola_management_program":[{"name":"tola_management_program-feca61b7873f2fd0e205.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/tola_management_program-feca61b7873f2fd0e205.js"},{"name":"tola_management_program-feca61b7873f2fd0e205.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/tola_management_program-feca61b7873f2fd0e205.js.map"}],"tola_management_user":[{"name":"tola_management_user-2e62a5cc5ee41288dcc0.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/tola_management_user-2e62a5cc5ee41288dcc0.js"},{"name":"tola_management_user-2e62a5cc5ee41288dcc0.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/tola_management_user-2e62a5cc5ee41288dcc0.js.map"}],"vendors":[{"name":"vendors-0c0545a78ffc4ebff1c9.css","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/vendors-0c0545a78ffc4ebff1c9.css"},{"name":"vendors-5c9fb0cb6044de5e5456.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/vendors-5c9fb0cb6044de5e5456.js"},{"name":"vendors-0c0545a78ffc4ebff1c9.css.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/vendors-0c0545a78ffc4ebff1c9.css.map"},{"name":"vendors-5c9fb0cb6044de5e5456.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/vendors-5c9fb0cb6044de5e5456.js.map"}]}}
\ No newline at end of file
+{"status":"done","chunks":{"audit_log":[{"name":"audit_log-7a0e288eaf6a936df408.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/audit_log-7a0e288eaf6a936df408.js"},{"name":"audit_log-7a0e288eaf6a936df408.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/audit_log-7a0e288eaf6a936df408.js.map"}],"base":[{"name":"base-41e082a648aa1a38fbc4.css","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/base-41e082a648aa1a38fbc4.css"},{"name":"base-702c52ce47930ba15f84.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/base-702c52ce47930ba15f84.js"},{"name":"base-41e082a648aa1a38fbc4.css.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/base-41e082a648aa1a38fbc4.css.map"},{"name":"base-702c52ce47930ba15f84.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/base-702c52ce47930ba15f84.js.map"}],"document_list":[{"name":"document_list-4bf5d1e03d38a6eaca94.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/document_list-4bf5d1e03d38a6eaca94.js"},{"name":"document_list-4bf5d1e03d38a6eaca94.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/document_list-4bf5d1e03d38a6eaca94.js.map"}],"program_page":[{"name":"program_page-fff173154048bae63e32.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/program_page-fff173154048bae63e32.js"},{"name":"program_page-fff173154048bae63e32.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/program_page-fff173154048bae63e32.js.map"}],"runtime":[{"name":"runtime-618bcded6741c4c27fdf.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/runtime-618bcded6741c4c27fdf.js"},{"name":"runtime-618bcded6741c4c27fdf.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/runtime-618bcded6741c4c27fdf.js.map"}],"tola_management_country":[{"name":"tola_management_country-d2d40a6be9de670de4c2.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/tola_management_country-d2d40a6be9de670de4c2.js"},{"name":"tola_management_country-d2d40a6be9de670de4c2.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/tola_management_country-d2d40a6be9de670de4c2.js.map"}],"tola_management_organization":[{"name":"tola_management_organization-5271c5c80db2208426b1.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/tola_management_organization-5271c5c80db2208426b1.js"},{"name":"tola_management_organization-5271c5c80db2208426b1.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/tola_management_organization-5271c5c80db2208426b1.js.map"}],"tola_management_program":[{"name":"tola_management_program-1c0ce8637a72447286c3.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/tola_management_program-1c0ce8637a72447286c3.js"},{"name":"tola_management_program-1c0ce8637a72447286c3.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/tola_management_program-1c0ce8637a72447286c3.js.map"}],"tola_management_user":[{"name":"tola_management_user-3a98142a4e1ec567b01d.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/tola_management_user-3a98142a4e1ec567b01d.js"},{"name":"tola_management_user-3a98142a4e1ec567b01d.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/tola_management_user-3a98142a4e1ec567b01d.js.map"}],"vendors":[{"name":"vendors-0c0545a78ffc4ebff1c9.css","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/vendors-0c0545a78ffc4ebff1c9.css"},{"name":"vendors-5c9fb0cb6044de5e5456.js","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/vendors-5c9fb0cb6044de5e5456.js"},{"name":"vendors-0c0545a78ffc4ebff1c9.css.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/vendors-0c0545a78ffc4ebff1c9.css.map"},{"name":"vendors-5c9fb0cb6044de5e5456.js.map","path":"/Users/paul/Repos/TolaActivity/build/dev-dist/vendors-5c9fb0cb6044de5e5456.js.map"}]}}
\ No newline at end of file
diff --git a/webpack-stats.json b/webpack-stats.json
index e18c2f56..05f836a3 100644
--- a/webpack-stats.json
+++ b/webpack-stats.json
@@ -1 +1 @@
-{"status":"done","chunks":{"runtime":[{"name":"runtime-ec2944dd8b20ec099bf3.js","path":"/Users/paul/Repos/TolaActivity/build/dist/runtime-ec2944dd8b20ec099bf3.js"}],"vendors":[{"name":"vendors-42e30866d827e6b06bb1.css","path":"/Users/paul/Repos/TolaActivity/build/dist/vendors-42e30866d827e6b06bb1.css"},{"name":"vendors-47bd47fcbeb192086d8b.js","path":"/Users/paul/Repos/TolaActivity/build/dist/vendors-47bd47fcbeb192086d8b.js"}],"audit_log":[{"name":"audit_log-28b6b761e87ded230c20.js","path":"/Users/paul/Repos/TolaActivity/build/dist/audit_log-28b6b761e87ded230c20.js"}],"base":[{"name":"base-faf56600e8452e84ab36.css","path":"/Users/paul/Repos/TolaActivity/build/dist/base-faf56600e8452e84ab36.css"},{"name":"base-7860ec9e0d43417984e1.js","path":"/Users/paul/Repos/TolaActivity/build/dist/base-7860ec9e0d43417984e1.js"}],"document_list":[{"name":"document_list-a1a50af96563ed667db5.js","path":"/Users/paul/Repos/TolaActivity/build/dist/document_list-a1a50af96563ed667db5.js"}],"program_page":[{"name":"program_page-4470e563d6238a23d44b.js","path":"/Users/paul/Repos/TolaActivity/build/dist/program_page-4470e563d6238a23d44b.js"}],"tola_management_country":[{"name":"tola_management_country-04ab318009aaae859046.js","path":"/Users/paul/Repos/TolaActivity/build/dist/tola_management_country-04ab318009aaae859046.js"}],"tola_management_organization":[{"name":"tola_management_organization-0c191946c56ef13da563.js","path":"/Users/paul/Repos/TolaActivity/build/dist/tola_management_organization-0c191946c56ef13da563.js"}],"tola_management_program":[{"name":"tola_management_program-f3cede18bd956db87a0f.js","path":"/Users/paul/Repos/TolaActivity/build/dist/tola_management_program-f3cede18bd956db87a0f.js"}],"tola_management_user":[{"name":"tola_management_user-f52a05a8a0213477e2cc.js","path":"/Users/paul/Repos/TolaActivity/build/dist/tola_management_user-f52a05a8a0213477e2cc.js"}]}}
\ No newline at end of file
+{"status":"done","chunks":{"runtime":[{"name":"runtime-ec2944dd8b20ec099bf3.js","path":"/Users/paul/Repos/TolaActivity/build/dist/runtime-ec2944dd8b20ec099bf3.js"}],"vendors":[{"name":"vendors-42e30866d827e6b06bb1.css","path":"/Users/paul/Repos/TolaActivity/build/dist/vendors-42e30866d827e6b06bb1.css"},{"name":"vendors-47bd47fcbeb192086d8b.js","path":"/Users/paul/Repos/TolaActivity/build/dist/vendors-47bd47fcbeb192086d8b.js"}],"audit_log":[{"name":"audit_log-615317e6f51428b2da6e.js","path":"/Users/paul/Repos/TolaActivity/build/dist/audit_log-615317e6f51428b2da6e.js"}],"base":[{"name":"base-6731d2e0b3b396102f05.css","path":"/Users/paul/Repos/TolaActivity/build/dist/base-6731d2e0b3b396102f05.css"},{"name":"base-84ad999e3b8337cb7619.js","path":"/Users/paul/Repos/TolaActivity/build/dist/base-84ad999e3b8337cb7619.js"}],"document_list":[{"name":"document_list-a1a50af96563ed667db5.js","path":"/Users/paul/Repos/TolaActivity/build/dist/document_list-a1a50af96563ed667db5.js"}],"program_page":[{"name":"program_page-4470e563d6238a23d44b.js","path":"/Users/paul/Repos/TolaActivity/build/dist/program_page-4470e563d6238a23d44b.js"}],"tola_management_country":[{"name":"tola_management_country-04ab318009aaae859046.js","path":"/Users/paul/Repos/TolaActivity/build/dist/tola_management_country-04ab318009aaae859046.js"}],"tola_management_organization":[{"name":"tola_management_organization-9ed9709b0a49919db259.js","path":"/Users/paul/Repos/TolaActivity/build/dist/tola_management_organization-9ed9709b0a49919db259.js"}],"tola_management_program":[{"name":"tola_management_program-89f28987e6b43e70cb39.js","path":"/Users/paul/Repos/TolaActivity/build/dist/tola_management_program-89f28987e6b43e70cb39.js"}],"tola_management_user":[{"name":"tola_management_user-73052b4e0cf7339e2fa4.js","path":"/Users/paul/Repos/TolaActivity/build/dist/tola_management_user-73052b4e0cf7339e2fa4.js"}]}}
\ No newline at end of file