From 90cbd23aafcd7791becbe57f79bb5c0f2adf30cc Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Sat, 23 Mar 2019 13:24:40 -0600 Subject: [PATCH 01/20] partial #1276: expanded changeset styling This needs some serious design love --- js/components/expander.js | 6 ++--- .../user/components/edit_user_history.js | 24 ++++++++++--------- scss/components/_tola_management.scss | 24 ++++++++++++------- 3 files changed, 31 insertions(+), 23 deletions(-) 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/user/components/edit_user_history.js b/js/pages/tola_management_pages/user/components/edit_user_history.js index 8a7ca9f2..5ef05207 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 @@ -10,30 +10,32 @@ const status_options = [ ] const ChangesetEntry = ({name, type, data}) => { - return

{name}: {(data != undefined && data != null)?data.toString():'N/A'}

+ return
{name}: {(data != undefined && data != null)?data.toString():'N/A'}
} const ProgramChangesetEntry = ({data, timeframe}) => { - return
+ 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}

+
+ {id} +
{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}

+
+ {id} +
{gettext("Program")}: {program[timeframe].program}
+
{gettext("Country")}: {program[timeframe].country}
+
{gettext("Role")}: {program[timeframe].role}
)}
diff --git a/scss/components/_tola_management.scss b/scss/components/_tola_management.scss index 0225beb3..da94ecda 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; - } } .edit-user-programs { @@ -101,9 +97,23 @@ } } -.expander { +// Expanding change logs +.changelog-entry {} +.changelog-entry__expanding { + // expanding child element overflow: hidden; } +.changelog-entry__expand-trigger {} + +// changesets inside change log +.changeset {} +.changeset__row { + // collects a group of changes made at the same time + border-bottom: 1px solid $gray-200; + padding: 5px; +} +.changeset__change { +} /* Safari */ @-webkit-keyframes spin { @@ -174,10 +184,6 @@ table.admin-list__table { th, td { vertical-align: top; } - - .expand-section { - width: 10%; - } } .virtualized-table__wrapper { From 1a9c1c75baa40ab497ca0e7e6879391ce9fbddb2 Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Mon, 25 Mar 2019 12:50:47 -0700 Subject: [PATCH 02/20] (no-wrap for tabs in user pane) --- js/pages/tola_management_pages/user/components/user_editor.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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")} From 30f34c8b25ced371110ab3a81270fed0307a74d7 Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Mon, 25 Mar 2019 15:20:35 -0700 Subject: [PATCH 03/20] firebreak: country/program changesets --- .../user/components/edit_user_history.js | 140 +++++++++++------- scss/components/_tola_management.scss | 14 ++ 2 files changed, 100 insertions(+), 54 deletions(-) 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 5ef05207..49d2c994 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 @@ -13,34 +13,45 @@ const ChangesetEntry = ({name, type, data}) => { return
    {name}: {(data != undefined && data != null)?data.toString():'N/A'}
    } -const ProgramChangesetEntry = ({data, timeframe}) => { - return
    +const ProgramChangesetEntry = ({data}) => { + return {Object.entries(data.countries).length > 0 && -
    -

    Countries

    - {Object.entries(data.countries).map(([id, country]) => -
    - {id} -
    {gettext("Country")}: {country[timeframe].country}
    -
    {gettext("Role")}: {country[timeframe].role}
    -
    - )} -
    + Object.entries(data.countries).map(([id, country]) => + + + + + +
    {gettext("Country")}: {country.prev.country}
    +
    {gettext("Role")}: {country.prev.role}
    + + +
    {gettext("Country")}: {country.new.country}
    +
    {gettext("Role")}: {country.new.role}
    + + + ) } {Object.entries(data.programs).length > 0 && -
    -

    Programs

    - {Object.entries(data.programs).map(([id, program]) => -
    - {id} -
    {gettext("Program")}: {program[timeframe].program}
    -
    {gettext("Country")}: {program[timeframe].country}
    -
    {gettext("Role")}: {program[timeframe].role}
    -
    - )} -
    + Object.entries(data.programs).map(([id, program]) => + + + + + +
    {gettext("Program")}: {program.prev.program}
    +
    {gettext("Country")}: {program.prev.country}
    +
    {gettext("Role")}: {program.prev.role}
    + + +
    {gettext("Program")}: {program.new.program}
    +
    {gettext("Country")}: {program.new.country}
    +
    {gettext("Role")}: {program.new.role}
    + + + ) } -
    + } export class EditUserHistory extends React.Component { @@ -90,7 +101,7 @@ export class EditUserHistory extends React.Component {
  • } - +
    @@ -100,48 +111,69 @@ export class EditUserHistory extends React.Component { - - {history.map(entry => { - if(entry.change_type == 'user_programs_updated') { - return + {history.map(entry => { + if(entry.change_type == 'user_programs_updated'){ + return + + + + + + + + + + } else { + return + + + + + + + + + } + {/*if(entry.change_type == 'user_programs_updated') { + return + - - - } else { + + } else { - return + return + - - - } - })} - + } */ } + })}
    {gettext("Date")}{gettext("New Entry")}
    {entry.id}:{entry.date}{entry.admin_user}{entry.change_type}
    {entry.id}:{entry.date}{entry.admin_user}{entry.change_type} + prev + + new +
    {entry.date} {entry.admin_user} {entry.change_type} - - - + + - - - + +
    {entry.date} {entry.admin_user} {entry.change_type} - - {entry.diff_list.map(changeset => { - return - })} - + + diff 1 + {entry.diff_list.map(changeset => { + return + })} - - {entry.diff_list.map(changeset => { - return - })} - + + diff 2 + {entry.diff_list.map(changeset => { + return + })}
    } diff --git a/scss/components/_tola_management.scss b/scss/components/_tola_management.scss index da94ecda..cfe6517b 100644 --- a/scss/components/_tola_management.scss +++ b/scss/components/_tola_management.scss @@ -98,6 +98,7 @@ } // Expanding change logs +// OLD SELECTORS, DELETE US! .changelog-entry {} .changelog-entry__expanding { // expanding child element @@ -115,6 +116,19 @@ .changeset__change { } +// NEW SELECTORS +.changelog { // +} +.changelog__entry { // each timestamped batch of DB updates; +} +.changelog__entry__header { // title row for changelog__entry; + background-color: $gray-200; + font-weight: bold; +} +.changelog__entry__row { // each DB row change; + +} + /* Safari */ @-webkit-keyframes spin { 0% { -webkit-transform: rotate(0deg); } From 427a3941da1af8b67ae86960b3ca2c058be84131 Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Mon, 25 Mar 2019 16:14:39 -0700 Subject: [PATCH 04/20] user profile changesets --- .../user/components/edit_user_history.js | 46 +++++-------------- 1 file changed, 12 insertions(+), 34 deletions(-) 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 49d2c994..c4d425f2 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 @@ -10,7 +10,9 @@ const status_options = [ ] const ChangesetEntry = ({name, type, data}) => { - return
    {name}: {(data != undefined && data != null)?data.toString():'N/A'}
    + return
    + {name}: {(data != undefined && data != null)?data.toString():'N/A'} +
    } const ProgramChangesetEntry = ({data}) => { @@ -115,7 +117,7 @@ export class EditUserHistory extends React.Component { if(entry.change_type == 'user_programs_updated'){ return
    - + @@ -125,54 +127,30 @@ export class EditUserHistory extends React.Component { } else { return - - - - - - - - - } - {/*if(entry.change_type == 'user_programs_updated') { - return - + - - + + - - } else { - - return - - - + + + - } */ } + + } })}
    {entry.id}:{entry.date}{entry.date} {entry.admin_user} {entry.change_type}
    {entry.id}:{entry.date}{entry.admin_user}{entry.change_type} - prev - - new -
    {entry.date} {entry.admin_user} {entry.change_type} - - - -
    {entry.date}{entry.admin_user}{entry.change_type} - diff 1 {entry.diff_list.map(changeset => { return })} - diff 2 {entry.diff_list.map(changeset => { return })}
    From 764038b75fc55b3d520a4af8d9fe648dad14f1b3 Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Mon, 25 Mar 2019 16:15:26 -0700 Subject: [PATCH 05/20] globally replace "N/A" with em-dash in tola_management --- tola_management/models.py | 22 +++++++++++----------- tola_management/programadmin.py | 5 +++-- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/tola_management/models.py b/tola_management/models.py index fad2e05d..af9a2795 100755 --- a/tola_management/models.py +++ b/tola_management/models.py @@ -27,13 +27,13 @@ def diff(previous, new): diff_list.append({ "name": p_field, "prev": p[p_field], - "new": 'N/A' + "new": '—' }) if n_field and n_field not in p: diff_list.append({ "name": n_field, - "prev": 'N/A', + "prev": '—', "new": n[n_field] }) @@ -90,13 +90,13 @@ def access_diff(p, n): diff_list.append({ "name": p_field, "prev": p[p_field], - "new": {k: 'N/A' for k, _ in p[p_field].iteritems()}, + "new": {k: '—' for k, _ in p[p_field].iteritems()}, }) if n_field and n_field not in p: diff_list.append({ "name": n_field, - "prev": {k: 'N/A' for k, _ in n[n_field].iteritems()}, + "prev": {k: '—' for k, _ in n[n_field].iteritems()}, "new": n[n_field] }) @@ -176,15 +176,15 @@ def diff_list(self): for diff in diff_list: if diff["name"] == 'targets': - if diff["prev"] == 'N/A': + if diff["prev"] == '—': diff["prev"] = { - n["id"]: {"name": n.get("name"), "value": 'N/A', "id": n["id"]} for k, n in diff["new"].iteritems() + n["id"]: {"name": n.get("name"), "value": '—', "id": n["id"]} for k, n in diff["new"].iteritems() } continue - if diff["new"] == 'N/A': + if diff["new"] == '—': diff["new"] = { - p["id"]: {"name": p.get("name"), "value": 'N/A', "id": p["id"]} for k, p in diff["prev"].iteritems() + p["id"]: {"name": p.get("name"), "value": '—', "id": p["id"]} for k, p in diff["prev"].iteritems() } continue @@ -194,7 +194,7 @@ def diff_list(self): if prev_id and prev_id not in diff["new"]: new[prev_id] = { "name": diff["prev"][prev_id].get('name'), - "value": 'N/A', + "value": '—', "id": diff["prev"][prev_id].get('id') } @@ -207,7 +207,7 @@ def diff_list(self): if new_id and new_id not in diff["prev"]: prev[new_id] = { "name": diff["new"][new_id].get('name'), - "value": 'N/A', + "value": '—', "id": diff["new"][new_id].get('id') } @@ -299,7 +299,7 @@ def log_result_created(user, indicator, created_result): organization=user.tola_user.organization, indicator=indicator, change_type="result_created", - rationale='N/A', + rationale='—', previous_entry=None, new_entry=json.dumps(created_result.logged_fields, cls=DjangoJSONEncoder) ) diff --git a/tola_management/programadmin.py b/tola_management/programadmin.py index 29e6cf52..07260375 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 @@ -353,8 +354,8 @@ def export_audit_log(self, request, pk=None): ws.append([ row.date, - row.indicator.number if row.indicator else 'N/A', - row.indicator.name if row.indicator else 'N/A', + row.indicator.number if row.indicator else '—', + row.indicator.name if row.indicator else '—', row.user.name, row.organization.name, row.change_type, From c372f5478739d5d8f2effb966fcf0b96e2863aea Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Mon, 25 Mar 2019 16:38:02 -0700 Subject: [PATCH 06/20] #1276: collapse display of user changelog a wee bit This is in bad need of componentization --- .../user/components/edit_user_history.js | 26 ++++++++----------- scss/components/_tola_management.scss | 1 - 2 files changed, 11 insertions(+), 16 deletions(-) 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 c4d425f2..661eef82 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 @@ -106,33 +106,29 @@ export class EditUserHistory extends React.Component { - - - - - + + + + + {history.map(entry => { if(entry.change_type == 'user_programs_updated'){ return - - - - - + + + } else { return - - - - - + + + diff --git a/scss/components/_tola_management.scss b/scss/components/_tola_management.scss index cfe6517b..77e73b42 100644 --- a/scss/components/_tola_management.scss +++ b/scss/components/_tola_management.scss @@ -123,7 +123,6 @@ } .changelog__entry__header { // title row for changelog__entry; background-color: $gray-200; - font-weight: bold; } .changelog__entry__row { // each DB row change; From 1ddc8f5f04eb59cc6e885deb9c1c14e2c686625a Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Mon, 25 Mar 2019 17:41:13 -0700 Subject: [PATCH 07/20] #1276: User changelog displays OK but needs refactor --- .../user/components/edit_user_history.js | 54 ++++++++++++------- 1 file changed, 35 insertions(+), 19 deletions(-) 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 661eef82..f44755f4 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 @@ -10,7 +10,7 @@ const status_options = [ ] const ChangesetEntry = ({name, type, data}) => { - return
    + return
    {name}: {(data != undefined && data != null)?data.toString():'N/A'}
    } @@ -24,12 +24,16 @@ const ProgramChangesetEntry = ({data}) => {
    ) @@ -41,14 +45,18 @@ const ProgramChangesetEntry = ({data}) => { ) @@ -119,7 +127,9 @@ export class EditUserHistory extends React.Component { - + + + @@ -128,21 +138,27 @@ export class EditUserHistory extends React.Component { - + + + From 34605a79bb4d11c8d4d54069cc75b0caaae80b48 Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Mon, 25 Mar 2019 17:41:27 -0700 Subject: [PATCH 08/20] (trivial: remove superfluous "Add User" text) --- js/pages/tola_management_pages/user/views.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/pages/tola_management_pages/user/views.js b/js/pages/tola_management_pages/user/views.js index 52a4023e..f90b5425 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( From 01fa4793980f240fc34b71aa1b30374397b4bc3c Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Mon, 25 Mar 2019 18:31:09 -0700 Subject: [PATCH 09/20] half-stretch for entry columns --- .../user/components/edit_user_history.js | 4 ++-- scss/components/_tables.scss | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) 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 f44755f4..873ab4da 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 @@ -117,8 +117,8 @@ export class EditUserHistory extends React.Component { - - + + {history.map(entry => { 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%; +} From 7550fad5e6f1ebd1575e9131081fd817fc0e02ff Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Tue, 26 Mar 2019 12:13:56 -0700 Subject: [PATCH 10/20] User changelog has nicer components, #1276 related --- .../user/components/edit_user_history.js | 116 +++++++++--------- scss/components/_tola_management.scss | 21 ++-- tola/settings/test.py | 2 - 3 files changed, 69 insertions(+), 70 deletions(-) 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 873ab4da..40ed4abe 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 @@ -9,53 +9,85 @@ const status_options = [ {value: false, label: gettext('Inactive')} ] -const ChangesetEntry = ({name, type, data}) => { - return
    - {name}: {(data != undefined && data != null)?data.toString():'N/A'} -
    +const ChangeField = ({name, data}) => { + return
    + {name}: {(data != undefined && data != null)?data.toString():'—'} +
    +} + +const ChangeLogEntryHeader = ({data}) => { + return
    + + + + + + +} + +const ChangeLogEntryRow = ({data}) => { + return + + + + + + } -const ProgramChangesetEntry = ({data}) => { +const ProgramChangelogEntryRow = ({data}) => { return - {Object.entries(data.countries).length > 0 && - Object.entries(data.countries).map(([id, country]) => + {Object.entries(data.diff_list.countries).length > 0 && + Object.entries(data.diff_list.countries).map(([id, country]) => ) } - {Object.entries(data.programs).length > 0 && - Object.entries(data.programs).map(([id, program]) => + {Object.entries(data.diff_list.programs).length > 0 && + Object.entries(data.diff_list.programs).map(([id, program]) => @@ -124,43 +156,13 @@ export class EditUserHistory extends React.Component { {history.map(entry => { if(entry.change_type == 'user_programs_updated'){ return - - - - - - - - + + } else { return - - - - - - - - - - - - - - + + } })} diff --git a/scss/components/_tola_management.scss b/scss/components/_tola_management.scss index 77e73b42..b094e5d1 100644 --- a/scss/components/_tola_management.scss +++ b/scss/components/_tola_management.scss @@ -106,16 +106,6 @@ } .changelog-entry__expand-trigger {} -// changesets inside change log -.changeset {} -.changeset__row { - // collects a group of changes made at the same time - border-bottom: 1px solid $gray-200; - padding: 5px; -} -.changeset__change { -} - // NEW SELECTORS .changelog { //
    {gettext("Date")}{gettext("Admin")}{gettext("Change Type")}{gettext("Previous Entry")}{gettext("New Entry")}{gettext("Date")}{gettext("Admin")}{gettext("Change Type")}{gettext("Previous Entry")}{gettext("New Entry")}
    {entry.date}{entry.admin_user}{entry.change_type}{entry.date}{entry.admin_user} {entry.change_type}
    {entry.date}{entry.admin_user}{entry.change_type}{entry.date}{entry.admin_user} {gettext("User profile")}
    -
    {gettext("Country")}: {country.prev.country}
    -
    {gettext("Role")}: {country.prev.role}
    +
    +
    {gettext("Country")}: {country.prev.country}
    +
    {gettext("Role")}: {country.prev.role}
    +
    -
    {gettext("Country")}: {country.new.country}
    -
    {gettext("Role")}: {country.new.role}
    +
    +
    {gettext("Country")}: {country.new.country}
    +
    {gettext("Role")}: {country.new.role}
    +
    -
    {gettext("Program")}: {program.prev.program}
    -
    {gettext("Country")}: {program.prev.country}
    -
    {gettext("Role")}: {program.prev.role}
    +
    +
    {gettext("Program")}: {program.prev.program}
    +
    {gettext("Country")}: {program.prev.country}
    +
    {gettext("Role")}: {program.prev.role}
    +
    -
    {gettext("Program")}: {program.new.program}
    -
    {gettext("Country")}: {program.new.country}
    -
    {gettext("Role")}: {program.new.role}
    +
    +
    {gettext("Program")}: {program.new.program}
    +
    {gettext("Country")}: {program.new.country}
    +
    {gettext("Role")}: {program.new.role}
    +
    {entry.date} {entry.admin_user} {entry.change_type}{entry.change_type}
    {entry.date} {entry.admin_user} {gettext("User profile")}{entry.change_type}
    - {entry.diff_list.map(changeset => { - return - })} +
    + {entry.diff_list.map(changeset => { + return + })} +
    - {entry.diff_list.map(changeset => { - return - })} +
    + {entry.diff_list.map(changeset => { + return + })} +
    {gettext("Date")} {gettext("Admin")} {gettext("Change Type")}{gettext("Previous Entry")}{gettext("New Entry")}{gettext("Previous Entry")}{gettext("New Entry")}
    {data.date}{data.admin_user}{data.change_type}
    +
    + {data.diff_list.map((changeset, id) => + + )} +
    +
    +
    + {data.diff_list.map((changeset, id) => + + )} +
    +
    -
    -
    {gettext("Country")}: {country.prev.country}
    -
    {gettext("Role")}: {country.prev.role}
    +
    + +
    -
    -
    {gettext("Country")}: {country.new.country}
    -
    {gettext("Role")}: {country.new.role}
    +
    + +
    -
    -
    {gettext("Program")}: {program.prev.program}
    -
    {gettext("Country")}: {program.prev.country}
    -
    {gettext("Role")}: {program.prev.role}
    +
    + + +
    -
    -
    {gettext("Program")}: {program.new.program}
    -
    {gettext("Country")}: {program.new.country}
    -
    {gettext("Role")}: {program.new.role}
    +
    + + +
    {entry.date}{entry.admin_user}{entry.change_type}
    {entry.date}{entry.admin_user}{entry.change_type}
    -
    - {entry.diff_list.map(changeset => { - return - })} -
    -
    -
    - {entry.diff_list.map(changeset => { - return - })} -
    -
    } @@ -125,7 +115,16 @@ 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 } /* Safari */ diff --git a/tola/settings/test.py b/tola/settings/test.py index 81f6aab4..22edc6eb 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": "", }, From be2cf8df021eb908517abeeca5587c91c477fd8b Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Tue, 26 Mar 2019 13:04:19 -0700 Subject: [PATCH 11/20] changelogentry component --- .../user/components/edit_user_history.js | 30 +++++++++++-------- 1 file changed, 17 insertions(+), 13 deletions(-) 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 40ed4abe..0c71a959 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 @@ -96,6 +96,20 @@ const ProgramChangelogEntryRow = ({data}) => { } +const ChangeLogEntry = ({data}) => { + if(data.change_type == 'user_programs_updated'){ + return + + + + } else { + return + + + + } +} + export class EditUserHistory extends React.Component { constructor(props) { @@ -153,19 +167,9 @@ export class EditUserHistory extends React.Component { - {history.map(entry => { - if(entry.change_type == 'user_programs_updated'){ - return - - - - } else { - return - - - - } - })} + {history.map((entry, id) => + + )}
    {gettext("New Entry")}
    } From e9d918ba76d2a7471739341522aea56096ff6a6d Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Tue, 26 Mar 2019 14:26:51 -0700 Subject: [PATCH 12/20] ProgramChangelogEntryRow component is superfluous --- .../user/components/edit_user_history.js | 153 +++++++++--------- 1 file changed, 73 insertions(+), 80 deletions(-) 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 0c71a959..1b45b6ca 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,7 +2,6 @@ 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' const status_options = [ {value: true, label: gettext('Active')}, @@ -26,88 +25,82 @@ const ChangeLogEntryHeader = ({data}) => { } const ChangeLogEntryRow = ({data}) => { - return - - - - -
    - {data.diff_list.map((changeset, id) => - - )} -
    - - -
    - {data.diff_list.map((changeset, id) => - - )} -
    - - -} - -const ProgramChangelogEntryRow = ({data}) => { - 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]) => - - - - - -
    - - - -
    - - -
    - - - -
    - - - ) - } -
    + 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}) => { - if(data.change_type == 'user_programs_updated'){ - return - - - - } else { - return - - - - } + return + + + } export class EditUserHistory extends React.Component { From cd871eaadb0f0534cfce456367d28a884d9eabfb Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Tue, 26 Mar 2019 16:50:27 -0700 Subject: [PATCH 13/20] =?UTF-8?q?So,=20hey=E2=80=A6all=20these=20changelog?= =?UTF-8?q?s=20could=20be=20using=20the=20same=20component=3F=20#1276?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- js/components/changelog.js | 115 ++++++++++++++++++ .../components/edit_organization_history.js | 40 +----- .../program/components/program_history.js | 40 +----- .../user/components/edit_user_history.js | 110 +---------------- 4 files changed, 125 insertions(+), 180 deletions(-) create mode 100644 js/components/changelog.js diff --git a/js/components/changelog.js b/js/components/changelog.js new file mode 100644 index 00000000..58d0c94d --- /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():'—'} +
    +} + +const ChangeLogEntryHeader = ({data}) => { + return + {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 + + + + + + + + + + {data.map((entry, id) => + + )} +
    {gettext("Date")}{gettext("Admin")}{gettext("Change Type")}{gettext("Previous Entry")}{gettext("New Entry")}
    +} + +export default ChangeLog 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 f1fb4218..7e5d80fd 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}) => { - return

    {name}: {(data != undefined && data != null)?data.toString():'N/A'}

    -} - export default class EditOrganizationHistory extends React.Component { constructor(props) { @@ -60,38 +57,9 @@ export default class EditOrganizationHistory extends React.Component {
    - - - - - - - - - - - - {this.props.organizationHistoryData.map(entry => - - - - - - )} - -
    {gettext("Date")}{gettext("Admin User")}{gettext("Change Type")}{gettext("Previous Entry")}{gettext("New Entry")}
    {entry.date}{entry.admin_user}{entry.change_type} - - {entry.diff_list.map(changeset => { - return - })} - - - - {entry.diff_list.map(changeset => { - return - })} - -
    + + +
    } } 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 22a09797..c82fa6b0 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}) => { - return

    {name}: {(data != undefined && data != null)?data.toString():'N/A'}

    -} - @observer export class ProgramHistory extends React.Component { @@ -62,38 +59,9 @@ export class ProgramHistory extends React.Component {
    - - - - - - - - - - - - {this.props.history.map(entry => - - - - - - )} - -
    {gettext("Date")}{gettext("Admin User")}{gettext("Change Type")}{gettext("Previous Entry")}{gettext("New Entry")}
    {entry.date}{entry.admin_user}{entry.change_type} - - {entry.diff_list.map(changeset => { - return - })} - - - - {entry.diff_list.map(changeset => { - return - })} - -
    + + +
    } } 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 1b45b6ca..61f19a1a 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,106 +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 ChangeLog from 'components/changelog' const status_options = [ {value: true, label: gettext('Active')}, {value: false, label: gettext('Inactive')} ] -const ChangeField = ({name, data}) => { - return
    - {name}: {(data != undefined && data != null)?data.toString():'—'} -
    -} - -const ChangeLogEntryHeader = ({data}) => { - return - {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 - - - -} export class EditUserHistory extends React.Component { @@ -150,20 +57,7 @@ export class EditUserHistory extends React.Component {
    } - - - - - - - - - - - {history.map((entry, id) => - - )} -
    {gettext("Date")}{gettext("Admin")}{gettext("Change Type")}{gettext("Previous Entry")}{gettext("New Entry")}
    + } } From 93a02045ff9553717617f932ec07f7d2bc17fe48 Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Tue, 26 Mar 2019 17:17:22 -0700 Subject: [PATCH 14/20] Audit log (from IPTT page) is different! Doesn't use ChangeLog #1276 and hey, what is `map_pretty_change_type()`? That might be useful for #1306 --- .../tola_management_pages/audit_log/views.js | 74 ++++++++++--------- scss/components/_tola_management.scss | 10 +++ 2 files changed, 48 insertions(+), 36 deletions(-) diff --git a/js/pages/tola_management_pages/audit_log/views.js b/js/pages/tola_management_pages/audit_log/views.js index 835a0972..1ba406c2 100644 --- a/js/pages/tola_management_pages/audit_log/views.js +++ b/js/pages/tola_management_pages/audit_log/views.js @@ -73,7 +73,7 @@ const indicator_changeset_name_map = { const IndicatorChangeset = ({data, name}) => { const mapped_data = (() => { - if (data == 'N/A') return data + if (data == '—') return data switch(name) { case 'unit_of_measure_type': @@ -88,16 +88,16 @@ const IndicatorChangeset = ({data, name}) => { } })() if(name == 'targets') { - return
    -

    Targets

    + return
    +

    Targets

    {Object.entries(data).map(([id, target]) => { - return

    {target.name}: {target.value}

    + return
    {target.name}: {target.value}
    })}
    } else { - return

    - {indicator_changeset_name_map[name]}: {(mapped_data !== null && mapped_data !== undefined)?mapped_data.toString():'N/A'} -

    + return
    + {indicator_changeset_name_map[name]}: {(mapped_data !== null && mapped_data !== undefined)?mapped_data.toString():'—'} +
    } } @@ -128,50 +128,52 @@ class ChangesetEntry extends React.Component { export const IndexView = observer( ({store}) => { - return
    + return
    - {gettext("Export to Excel")} + -
    +
    - +
    - - - - - - - - - + + + + + + + + + - - {store.log_rows.map(data => + {/* Note that this changelog is different than others. Only 1 tbody! */} + {store.log_rows.map(data => - - {/* SWEET FANCY MOSES WHAT IS THIS */} + - - + )}
    {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")}
    {data.date} {(data.indicator)?data.indicator.number:'N/A'} {(data.indicator)?data.indicator.name:'N/A'} {data.user} {data.organization}{map_pretty_change_type(data.change_type)} - - {data.diff_list.map(changeset => { - return - })} - + {map_pretty_change_type(data.change_type)} + {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/scss/components/_tola_management.scss b/scss/components/_tola_management.scss index b094e5d1..0e44503a 100644 --- a/scss/components/_tola_management.scss +++ b/scss/components/_tola_management.scss @@ -126,6 +126,16 @@ .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 + border-top: 1px solid $gray-200; + margin-top: $grid-gutter-width/4; + padding-top: $grid-gutter-width/4; +} /* Safari */ @-webkit-keyframes spin { From c03f8fd7d80a553b83c3eea63900365c852bf597 Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Wed, 27 Mar 2019 11:33:45 -0700 Subject: [PATCH 15/20] finish up changelog styling & some audit changesets #1276 --- js/components/changelog.js | 4 ++-- js/pages/tola_management_pages/audit_log/views.js | 8 ++++---- scss/components/_tola_management.scss | 4 +++- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/js/components/changelog.js b/js/components/changelog.js index 58d0c94d..3f6e056d 100644 --- a/js/components/changelog.js +++ b/js/components/changelog.js @@ -7,7 +7,7 @@ const ChangeField = ({name, data}) => { } const ChangeLogEntryHeader = ({data}) => { - return + return {/* TODO: apply is-expanded dynamically */} {data.date} {data.admin_user} {data.change_type} @@ -96,7 +96,7 @@ const ChangeLogEntry = ({data}) => { } const ChangeLog = ({data}) => { - return + return
    diff --git a/js/pages/tola_management_pages/audit_log/views.js b/js/pages/tola_management_pages/audit_log/views.js index 1ba406c2..05b69ca7 100644 --- a/js/pages/tola_management_pages/audit_log/views.js +++ b/js/pages/tola_management_pages/audit_log/views.js @@ -44,9 +44,9 @@ const result_changeset_name_map = { const ResultChangeset = ({data, name}) => { if(name == 'evidence_url') { - return

    {result_changeset_name_map[name]}: {(data != 'N/A')?Link:data}

    + return
    {result_changeset_name_map[name]}: {(data != '—')?Link:data}
    } else { - return

    {result_changeset_name_map[name]}: {data}

    + return
    {result_changeset_name_map[name]}: {data}
    } } @@ -56,7 +56,7 @@ const program_dates_changset_name_map = { } const ProgramDatesChangeset = ({data, name}) => { - return

    {program_dates_changset_name_map[name]}: {data}

    + return
    {program_dates_changset_name_map[name]}: {data}
    } const indicator_changeset_name_map = { @@ -141,7 +141,7 @@ export const IndexView = observer(
    -
    {gettext("Date")}
    +
    diff --git a/scss/components/_tola_management.scss b/scss/components/_tola_management.scss index 0e44503a..1747a088 100644 --- a/scss/components/_tola_management.scss +++ b/scss/components/_tola_management.scss @@ -112,7 +112,9 @@ .changelog__entry { // each timestamped batch of DB updates; } .changelog__entry__header { // title row for changelog__entry; - background-color: $gray-200; + &.is-expanded { + background-color: $gray-200; + } } .changelog__entry__row { // each DB row change; } From 8e3421afcaa893ec169f89ce125b8ad645675c99 Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Wed, 27 Mar 2019 12:20:26 -0700 Subject: [PATCH 16/20] =?UTF-8?q?%s/=E2=80=94/N\/A/g=20was=20more=20proble?= =?UTF-8?q?matic=20than=20I=20anticipated?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- indicators/views/views_reports.py | 10 ++++----- js/components/changelog.js | 2 +- .../tola_management_pages/audit_log/views.js | 6 ++--- tola_management/models.py | 22 +++++++++---------- tola_management/programadmin.py | 4 ++-- 5 files changed, 22 insertions(+), 22 deletions(-) diff --git a/indicators/views/views_reports.py b/indicators/views/views_reports.py index 70ac5062..b9bec976 100644 --- a/indicators/views/views_reports.py +++ b/indicators/views/views_reports.py @@ -466,11 +466,11 @@ def prepare_indicators(self, reporttype, period, periods_date_ranges, indicators else: ind['lop_target'] = formatFloat(lop_target) except (ValueError, TypeError): - lop_target = u'—' + lop_target = u'N/A' ind['lop_target'] = lop_target # process lop_actual - lop_actual = u'—' + lop_actual = u'N/A' percent = u'' if ind['unit_of_measure_type'] == Indicator.NUMBER: if ind['actualsum'] is not None: @@ -482,7 +482,7 @@ def prepare_indicators(self, reporttype, period, periods_date_ranges, indicators try: ind['lop_actual'] = u"{}{}".format(formatFloat(lop_actual), percent) except TypeError: - ind['lop_actual'] = u'—' + ind['lop_actual'] = u'N/A' # process lop_percent_met try: @@ -528,7 +528,7 @@ def prepare_indicators(self, reporttype, period, periods_date_ranges, indicators if actual_val is not None and actual_val != '': ind[actual] = u"{}{}".format(formatFloat(actual_val), percent_sign) else: - ind[actual] = u'—' + ind[actual] = u'N/A' if reporttype == self.REPORT_TYPE_TARGETPERIODS: # process target_period target value @@ -719,7 +719,7 @@ def set_cell_value(cell, value, percent=False): else: # more catches? value = str(value) - if percent and len(value) > 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 index 3f6e056d..bb8c48a6 100644 --- a/js/components/changelog.js +++ b/js/components/changelog.js @@ -2,7 +2,7 @@ import React from 'react' const ChangeField = ({name, data}) => { return
    - {name}: {(data != undefined && data != null)?data.toString():'—'} + {name}: {(data != undefined && data != null)?data.toString():'N/A'}
    } diff --git a/js/pages/tola_management_pages/audit_log/views.js b/js/pages/tola_management_pages/audit_log/views.js index 05b69ca7..e256c0e7 100644 --- a/js/pages/tola_management_pages/audit_log/views.js +++ b/js/pages/tola_management_pages/audit_log/views.js @@ -44,7 +44,7 @@ const result_changeset_name_map = { const ResultChangeset = ({data, name}) => { if(name == 'evidence_url') { - return
    {result_changeset_name_map[name]}: {(data != '—')?Link:data}
    + return
    {result_changeset_name_map[name]}: {(data != 'N/A')?Link:data}
    } else { return
    {result_changeset_name_map[name]}: {data}
    } @@ -73,7 +73,7 @@ const indicator_changeset_name_map = { const IndicatorChangeset = ({data, name}) => { const mapped_data = (() => { - if (data == '—') return data + if (data == 'N/A') return data switch(name) { case 'unit_of_measure_type': @@ -96,7 +96,7 @@ const IndicatorChangeset = ({data, name}) => { } else { return
    - {indicator_changeset_name_map[name]}: {(mapped_data !== null && mapped_data !== undefined)?mapped_data.toString():'—'} + {indicator_changeset_name_map[name]}: {(mapped_data !== null && mapped_data !== undefined)?mapped_data.toString():'N/A'}
    } } diff --git a/tola_management/models.py b/tola_management/models.py index af9a2795..fad2e05d 100755 --- a/tola_management/models.py +++ b/tola_management/models.py @@ -27,13 +27,13 @@ def diff(previous, new): diff_list.append({ "name": p_field, "prev": p[p_field], - "new": '—' + "new": 'N/A' }) if n_field and n_field not in p: diff_list.append({ "name": n_field, - "prev": '—', + "prev": 'N/A', "new": n[n_field] }) @@ -90,13 +90,13 @@ def access_diff(p, n): diff_list.append({ "name": p_field, "prev": p[p_field], - "new": {k: '—' for k, _ in p[p_field].iteritems()}, + "new": {k: 'N/A' for k, _ in p[p_field].iteritems()}, }) if n_field and n_field not in p: diff_list.append({ "name": n_field, - "prev": {k: '—' for k, _ in n[n_field].iteritems()}, + "prev": {k: 'N/A' for k, _ in n[n_field].iteritems()}, "new": n[n_field] }) @@ -176,15 +176,15 @@ def diff_list(self): for diff in diff_list: if diff["name"] == 'targets': - if diff["prev"] == '—': + if diff["prev"] == 'N/A': diff["prev"] = { - n["id"]: {"name": n.get("name"), "value": '—', "id": n["id"]} for k, n in diff["new"].iteritems() + n["id"]: {"name": n.get("name"), "value": 'N/A', "id": n["id"]} for k, n in diff["new"].iteritems() } continue - if diff["new"] == '—': + if diff["new"] == 'N/A': diff["new"] = { - p["id"]: {"name": p.get("name"), "value": '—', "id": p["id"]} for k, p in diff["prev"].iteritems() + p["id"]: {"name": p.get("name"), "value": 'N/A', "id": p["id"]} for k, p in diff["prev"].iteritems() } continue @@ -194,7 +194,7 @@ def diff_list(self): if prev_id and prev_id not in diff["new"]: new[prev_id] = { "name": diff["prev"][prev_id].get('name'), - "value": '—', + "value": 'N/A', "id": diff["prev"][prev_id].get('id') } @@ -207,7 +207,7 @@ def diff_list(self): if new_id and new_id not in diff["prev"]: prev[new_id] = { "name": diff["new"][new_id].get('name'), - "value": '—', + "value": 'N/A', "id": diff["new"][new_id].get('id') } @@ -299,7 +299,7 @@ def log_result_created(user, indicator, created_result): organization=user.tola_user.organization, indicator=indicator, change_type="result_created", - rationale='—', + rationale='N/A', previous_entry=None, new_entry=json.dumps(created_result.logged_fields, cls=DjangoJSONEncoder) ) diff --git a/tola_management/programadmin.py b/tola_management/programadmin.py index 07260375..3b92fbc5 100644 --- a/tola_management/programadmin.py +++ b/tola_management/programadmin.py @@ -354,8 +354,8 @@ def export_audit_log(self, request, pk=None): ws.append([ row.date, - row.indicator.number if row.indicator else '—', - row.indicator.name if row.indicator else '—', + row.indicator.number if row.indicator else 'N/A', + row.indicator.name if row.indicator else 'N/A', row.user.name, row.organization.name, row.change_type, From ccc9ba119247d3a5b3fe341122bc4d7cc5a858ae Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Wed, 27 Mar 2019 12:24:56 -0700 Subject: [PATCH 17/20] Audit changelog now follows same design as other changelogs see also 93a02045 --- .../tola_management_pages/audit_log/views.js | 26 ++++++++++++++----- scss/components/_tola_management.scss | 3 --- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/js/pages/tola_management_pages/audit_log/views.js b/js/pages/tola_management_pages/audit_log/views.js index e256c0e7..02ea969e 100644 --- a/js/pages/tola_management_pages/audit_log/views.js +++ b/js/pages/tola_management_pages/audit_log/views.js @@ -89,7 +89,7 @@ const IndicatorChangeset = ({data, name}) => { })() if(name == 'targets') { return
    -

    Targets

    +

    {gettext('Targets changed')}

    {Object.entries(data).map(([id, target]) => { return
    {target.name}: {target.value}
    })} @@ -155,27 +155,39 @@ export const IndexView = observer(
    - {/* Note that this changelog is different than others. Only 1 tbody! */} - {store.log_rows.map(data => + {store.log_rows.map(data => + {/* SWEET FANCY MOSES WHAT IS THIS */} + + + + + + + + + + + - - )} + + + )}
    {gettext("Date and Time")}
    {gettext("Rationale")}
    {data.date} {(data.indicator)?data.indicator.number:'N/A'} {(data.indicator)?data.indicator.name:'N/A'} {data.user} {data.organization} {map_pretty_change_type(data.change_type)}
    {data.diff_list.map(changeset => { - return + return })} {data.diff_list.map(changeset => { - return + return })} {data.rationale}
    {data.rationale}
    diff --git a/scss/components/_tola_management.scss b/scss/components/_tola_management.scss index 1747a088..c02cddf4 100644 --- a/scss/components/_tola_management.scss +++ b/scss/components/_tola_management.scss @@ -134,9 +134,6 @@ .changelog__change__targets { // only on indicator report, ie. from IPTT // group of targets inside the prev/new component - border-top: 1px solid $gray-200; - margin-top: $grid-gutter-width/4; - padding-top: $grid-gutter-width/4; } /* Safari */ From f17c36e5c1caf849e74c9084f86f26b486ef69c5 Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Wed, 27 Mar 2019 14:07:04 -0700 Subject: [PATCH 18/20] add it to result changeset map in audit changelog --- js/pages/tola_management_pages/audit_log/views.js | 1 + 1 file changed, 1 insertion(+) diff --git a/js/pages/tola_management_pages/audit_log/views.js b/js/pages/tola_management_pages/audit_log/views.js index 02ea969e..167b8791 100644 --- a/js/pages/tola_management_pages/audit_log/views.js +++ b/js/pages/tola_management_pages/audit_log/views.js @@ -40,6 +40,7 @@ const result_changeset_name_map = { 'date': gettext('Date'), 'target': gettext('Target'), 'value': gettext('Value'), + 'id': gettext('ID'), } const ResultChangeset = ({data, name}) => { From 65981400475be1045a1afc6e8b5580b5633a5499 Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Wed, 27 Mar 2019 14:16:49 -0700 Subject: [PATCH 19/20] a little style help for expando trigger --- js/components/changelog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/components/changelog.js b/js/components/changelog.js index bb8c48a6..e604b765 100644 --- a/js/components/changelog.js +++ b/js/components/changelog.js @@ -8,7 +8,7 @@ const ChangeField = ({name, data}) => { const ChangeLogEntryHeader = ({data}) => { return {/* TODO: apply is-expanded dynamically */} - {data.date} +  {data.date} {data.admin_user} {data.change_type} From 6647ed44bb417e0732bccbfadbcf01627df57b77 Mon Sep 17 00:00:00 2001 From: Paul Souders Date: Fri, 29 Mar 2019 08:46:13 -0700 Subject: [PATCH 20/20] build bundle --- ...4.js => audit_log-7a0e288eaf6a936df408.js} | 106 ++++-- .../audit_log-7a0e288eaf6a936df408.js.map | 1 + .../audit_log-8f3ec9b285211b3b3934.js.map | 1 - .../base-41e082a648aa1a38fbc4.css} | 18 +- ...9873d8.js => base-702c52ce47930ba15f84.js} | 2 +- ...s.map => base-702c52ce47930ba15f84.js.map} | 2 +- ...t_organization-4c0e78fa1302d9fc5d80.js.map | 1 - ...ment_organization-5271c5c80db2208426b1.js} | 216 ++++++++++-- ...t_organization-5271c5c80db2208426b1.js.map | 1 + ...anagement_program-1c0ce8637a72447286c3.js} | 219 +++++++++--- ...gement_program-1c0ce8637a72447286c3.js.map | 1 + ...gement_program-feca61b7873f2fd0e205.js.map | 1 - ...anagement_user-2e62a5cc5ee41288dcc0.js.map | 1 - ...a_management_user-3a98142a4e1ec567b01d.js} | 313 +++++++++--------- ...anagement_user-3a98142a4e1ec567b01d.js.map | 1 + build/dist/audit_log-28b6b761e87ded230c20.js | 1 - build/dist/audit_log-615317e6f51428b2da6e.js | 1 + .../base-6731d2e0b3b396102f05.css} | 18 +- ...7984e1.js => base-84ad999e3b8337cb7619.js} | 0 ...ement_organization-0c191946c56ef13da563.js | 1 - ...ement_organization-9ed9709b0a49919db259.js | 1 + ...management_program-89f28987e6b43e70cb39.js | 1 + ...management_program-f3cede18bd956db87a0f.js | 1 - ...la_management_user-73052b4e0cf7339e2fa4.js | 1 + ...la_management_user-f52a05a8a0213477e2cc.js | 1 - webpack-stats-dev.json | 2 +- webpack-stats.json | 2 +- 27 files changed, 614 insertions(+), 300 deletions(-) rename build/dev-dist/{audit_log-8f3ec9b285211b3b3934.js => audit_log-7a0e288eaf6a936df408.js} (91%) create mode 100644 build/dev-dist/audit_log-7a0e288eaf6a936df408.js.map delete mode 100644 build/dev-dist/audit_log-8f3ec9b285211b3b3934.js.map rename build/{dist/base-faf56600e8452e84ab36.css => dev-dist/base-41e082a648aa1a38fbc4.css} (99%) rename build/dev-dist/{base-fdebc32420e55b9873d8.js => base-702c52ce47930ba15f84.js} (99%) rename build/dev-dist/{base-fdebc32420e55b9873d8.js.map => base-702c52ce47930ba15f84.js.map} (99%) delete mode 100644 build/dev-dist/tola_management_organization-4c0e78fa1302d9fc5d80.js.map rename build/dev-dist/{tola_management_organization-4c0e78fa1302d9fc5d80.js => tola_management_organization-5271c5c80db2208426b1.js} (91%) create mode 100644 build/dev-dist/tola_management_organization-5271c5c80db2208426b1.js.map rename build/dev-dist/{tola_management_program-feca61b7873f2fd0e205.js => tola_management_program-1c0ce8637a72447286c3.js} (92%) create mode 100644 build/dev-dist/tola_management_program-1c0ce8637a72447286c3.js.map delete mode 100644 build/dev-dist/tola_management_program-feca61b7873f2fd0e205.js.map delete mode 100644 build/dev-dist/tola_management_user-2e62a5cc5ee41288dcc0.js.map rename build/dev-dist/{tola_management_user-2e62a5cc5ee41288dcc0.js => tola_management_user-3a98142a4e1ec567b01d.js} (94%) create mode 100644 build/dev-dist/tola_management_user-3a98142a4e1ec567b01d.js.map delete mode 100644 build/dist/audit_log-28b6b761e87ded230c20.js create mode 100644 build/dist/audit_log-615317e6f51428b2da6e.js rename build/{dev-dist/base-a3666adfd3893f62c008.css => dist/base-6731d2e0b3b396102f05.css} (99%) rename build/dist/{base-7860ec9e0d43417984e1.js => base-84ad999e3b8337cb7619.js} (100%) delete mode 100644 build/dist/tola_management_organization-0c191946c56ef13da563.js create mode 100644 build/dist/tola_management_organization-9ed9709b0a49919db259.js create mode 100644 build/dist/tola_management_program-89f28987e6b43e70cb39.js delete mode 100644 build/dist/tola_management_program-f3cede18bd956db87a0f.js create mode 100644 build/dist/tola_management_user-73052b4e0cf7339e2fa4.js delete mode 100644 build/dist/tola_management_user-f52a05a8a0213477e2cc.js 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 \n \n \n \n \n \n \n \n \n \n \n \n {store.log_rows.map(data => \n \n \n \n \n \n \n {/* SWEET FANCY MOSES WHAT IS THIS */}\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n )}\n
    {gettext(\"Date and Time\")}{gettext(\"No.\")}{gettext(\"Indicator\")}{gettext(\"User\")}{gettext(\"Organization\")}{gettext(\"Change Type\")}{gettext(\"Previous Entry\")}{gettext(\"New Entry\")}{gettext(\"Rationale\")}
    {data.date}{(data.indicator)?data.indicator.number:'N/A'}{(data.indicator)?data.indicator.name:'N/A'}{data.user}{data.organization}{map_pretty_change_type(data.change_type)}
    \n {data.diff_list.map(changeset => {\n return \n })}\n \n {data.diff_list.map(changeset => {\n return \n })}\n {data.rationale}
    \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
    \n
    \n {children}\n
    \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 \n \n \n \n
    \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 \n \n \n \n \n \n \n \n \n \n \n \n {store.log_rows.map(data => \n \n \n \n \n \n \n \n \n \n )}\n \n
    {gettext(\"Date and Time\")}{gettext(\"No.\")}{gettext(\"Indicator\")}{gettext(\"User\")}{gettext(\"Organization\")}{gettext(\"Change Type\")}{gettext(\"Previous Entry\")}{gettext(\"New Entry\")}{gettext(\"Rationale\")}
    {data.date}{(data.indicator)?data.indicator.number:'N/A'}{(data.indicator)?data.indicator.name:'N/A'}{data.user}{data.organization}{map_pretty_change_type(data.change_type)}\n \n {data.diff_list.map(changeset => {\n return \n })}\n \n \n \n {data.diff_list.map(changeset => {\n return \n })}\n \n {data.rationale}
    \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
    \n
    \n {children}\n
    \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 \n \n \n \n
    \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: $(`
    ${inner}
    `).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
    \n \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
    \n \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: $(`
    ${inner}
    `).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
    \n \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
    \n \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
    \n
    \n {children}\n
    \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 \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 \n store.changeProgramFilter(e)}\n placeholder={gettext(\"None Selected\")}\n id=\"programs_filter\" />\n
    \n})\n\nconst OrganizationFilter = observer(({store, selections}) => {\n return
    \n \n store.changeOrganizationFilter(e)}\n placeholder={gettext(\"None Selected\")}\n id=\"organization_filter\" />\n
    \n})\n\nconst SectorFilter = observer(({store, selections}) => {\n return
    \n \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 \n store.changeOrganizationStatusFilter(e)}\n placeholder={gettext(\"None Selected\")}\n id=\"status_filter\" />\n
    \n
    \n \n \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 \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 \n \n \n \n
    \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 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 \n this.updateSectors(e)}\n placeholder={gettext(\"None Selected\")}\n id=\"sectors-input\" />\n
    \n
    \n \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 \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 \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 \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 \n this.updateModeOfContact(e.target.value) }\n className=\"form-control\"\n id=\"mode-of-contact-input\" />\n
    \n {this.props.new &&\n
    \n \n \n \n
    \n }\n {!this.props.new &&\n
    \n \n \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;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;AA4BA;AACA;AACA;AACA;AACA;AALA;AA3BA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AChBA;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;;;;;;;;;;;;;;;;;;;;;AC1DA;AACA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAIA;AACA;AACA;;;;;;;;;;;;ACbA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AACA;AAEA;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;AACA;AACA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AACA;AACA;AALA;AAOA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAIA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAIA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AACA;AACA;AAAA;AAAA;AAAA;AAEA;AAAA;AAEA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAPA;AAUA;AAAA;AAAA;AAAA;AAAA;AAEA;AACA;AAAA;AAAA;AAGA;AACA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AACA;AACA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AARA;AAFA;AAaA;AAAA;AACA;AAAA;AAEA;AACA;AACA;AAAA;AAAA;AAHA;AAFA;AAfA;AAFA;AAFA;AA8BA;AAAA;AAEA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAIA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAIA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AAIA;AAAA;AAnDA;AAbA;AAsEA;AAAA;AACA;AAAA;AACA;AAAA;AAGA;AACA;AACA;AAAA;AAAA;AAHA;AASA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpLA;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;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;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;AAIA;AAAA;AACA;AAAA;AACA;AADA;AAAA;AADA;AAMA;AAAA;AAWA;;;;AA9CA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACLA;AACA;AACA;AACA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AACA;AAAA;AAAA;AACA;AAEA;;;;;AAEA;AAAA;AACA;AADA;AACA;AAAA;AACA;AAAA;AAEA;AAAA;AAAA;AAFA;AACA;AAGA;AACA;AACA;AAFA;AANA;AAUA;AACA;;;AACA;AACA;AAEA;AACA;AADA;AAGA;;;AAEA;AACA;AACA;AADA;AAGA;;;AAEA;AACA;AACA;AAEA;AACA;AAAA;AAAA;AAHA;AAKA;;;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AACA;AAAA;AACA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAGA;AAAA;AAGA;;;;AAnDA;AACA;;;;;;;;;;;;;;;;;;;;;;;;;ACbA;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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AACA;AACA;AACA;AAEA;;;;AAGA;AASA;AACA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;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_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 \n this.onStatusChange(new_value)}\n />\n
    \n
    \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
    \n
    \n {children}\n
    \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 \n \n \n \n \n \n \n {data.map((entry, id) =>\n \n )}\n
    {gettext(\"Date\")}{gettext(\"Admin\")}{gettext(\"Change Type\")}{gettext(\"Previous Entry\")}{gettext(\"New Entry\")}
    \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 \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 \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 \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 \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 \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 \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 \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 \n {/* */}\n \n
    \n }\n {!this.props.new &&\n
    \n \n \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 \n \n \n \n
    \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 \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 \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 \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 \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 \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 \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 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 \n \n
    \n
    \n
    \n
    \n \n \n
    \n \n \n \n store.toggleBulkTargetsAll()}/>\n \n {gettext(\"Program\")}\n {gettext(\"Organizations\")}\n {gettext(\"Users\")}\n {gettext(\"Status\")}\n \n }\n Row={({Col, Row, data}) =>\n \n \n \n \n store.updateProgram(id, data)}\n onCreate={(new_program_data) => store.saveNewProgram(new_program_data)}\n sectorOptions={sectorFilterOptions}\n countryOptions={allCountryOptions}\n errors={store.editing_errors} />\n \n )}\n HistorySection={observer(() =>\n \n store.updateProgram(id, data)} />\n \n )}\n />\n \n }>\n \n store.toggleBulkTarget(data.id) }/>\n \n \n {data.id == 'new' &&\n
    \n  \n {data.name || \"New Program\"}\n
    \n }\n {data.id != 'new' &&\n
    store.toggleEditingTarget(data.id)} >\n  \n {data.name || \"New Program\"}\n
    \n }\n \n \n { organizationColumn(data)}\n \n \n {data.program_users ?  {data.program_users} users : '---' }\n \n {data.funding_status ? data.funding_status : '---'}\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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A;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 \n this.onStatusChange(new_value)}\n />\n
    \n
    \n \n \n
    \n \n \n \n \n \n \n \n \n \n \n \n {this.props.history.map(entry => \n \n \n \n \n \n )}\n \n
    {gettext(\"Date\")}{gettext(\"Admin User\")}{gettext(\"Change Type\")}{gettext(\"Previous Entry\")}{gettext(\"New Entry\")}
    {entry.date}{entry.admin_user}{entry.change_type}\n \n {entry.diff_list.map(changeset => {\n return \n })}\n \n \n \n {entry.diff_list.map(changeset => {\n return \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
    \n
    \n {children}\n
    \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 \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 \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 \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 \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 \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 \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 \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 \n {/* */}\n \n
    \n }\n {!this.props.new &&\n
    \n \n \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 \n \n \n \n
    \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 \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 \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 \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 \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 \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 \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 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 \n \n
    \n
    \n
    \n
    \n \n \n
    \n \n \n \n store.toggleBulkTargetsAll()}/>\n \n {gettext(\"Program\")}\n {gettext(\"Organizations\")}\n {gettext(\"Users\")}\n {gettext(\"Status\")}\n \n }\n Row={({Col, Row, data}) =>\n \n \n \n \n store.updateProgram(id, data)}\n onCreate={(new_program_data) => store.saveNewProgram(new_program_data)}\n sectorOptions={sectorFilterOptions}\n countryOptions={allCountryOptions}\n errors={store.editing_errors} />\n \n )}\n HistorySection={observer(() =>\n \n store.updateProgram(id, data)} />\n \n )}\n />\n \n }>\n \n store.toggleBulkTarget(data.id) }/>\n \n \n {data.id == 'new' &&\n
    \n  \n {data.name || \"New Program\"}\n
    \n }\n {data.id != 'new' &&\n
    store.toggleEditingTarget(data.id)} >\n  \n {data.name || \"New Program\"}\n
    \n }\n \n \n { organizationColumn(data)}\n \n \n {data.program_users ?  {data.program_users} users : '---' }\n \n {data.funding_status ? data.funding_status : '---'}\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.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 => )}\n \n }/>\n\n \n }\n
    \n
    \n\n
    \n \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 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 \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 \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 \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 \n this.updateTitle(e.target.value)}\n className=\"form-control\"\n id=\"user-title-input\" />\n
    \n
    \n \n this.updateEmail(e.target.value)}\n id=\"user-email-input\" />\n {e.email &&\n
    \n {e.email}\n
    \n }\n
    \n
    \n \n this.updatePhone(e.target.value)}\n className=\"form-control\"\n id=\"user-phone-input\" />\n
    \n
    \n \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 \n \n \n
    \n }\n {!this.props.new && !disabled &&\n
    \n \n \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
    \n
    \n {children}\n
    \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(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 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 \n store.changeOrganizationFilter(e)}\n isMulti={true}\n placeholder={selection_placeholder}\n id=\"organization_filter\" />\n
    \n
    \n \n store.changeUserStatusFilter(e)}\n placeholder={selection_placeholder}\n id=\"status_filter\" />\n
    \n
    \n \n store.changeAdminRoleFilter(e)}\n placeholder={selection_placeholder}\n id=\"admin_role_filter\" />\n
    \n \n
    \n \n \n
    \n
    \n
    \n
    \n \n \n
    \n store.users[id])}\n keyField=\"id\"\n HeaderRow={({Col, Row}) =>\n \n \n store.toggleBulkTargetsAll()}/>\n \n {gettext(\"User\")}\n {gettext(\"Organization\")}\n {gettext(\"Programs\")}\n {gettext(\"Admin Role\")}\n {gettext(\"Status\")}\n \n }\n Row={({Col, Row, data}) =>\n \n \n \n \n store.updateUserProfile(data.id, new_user_data)}\n onCreate={(new_user_data) => store.saveNewUser(new_user_data)}\n onCreateAndAddAnother={(new_user_data) => store.saveNewUserAndAddAnother(new_user_data)}\n organizations={store.organization_selections} />\n \n )}\n ProgramSection={observer(() =>\n \n store.saveUserPrograms(data.id, new_program_data)}/>\n \n )}\n HistorySection={observer(() =>\n \n store.resendRegistrationEmail(data.id)}\n onSave={(new_data) => store.updateUserIsActive(data.id, new_data)}/>\n \n )}\n />\n \n }>\n \n store.toggleBulkTarget(data.id) }/>\n \n \n
    store.toggleEditingTarget(data.id)} >\n  \n {data.name || \"---\"} {data.is_super && {gettext(\"Super Admin\")}}\n
    \n \n \n  \n {data.organization_name || \"---\"}\n \n \n \n  \n {data.user_programs} {gettext(\"programs\")}\n \n \n {data.is_admin?gettext('Yes'):gettext('No')}\n {data.is_active?gettext('Active'):gettext('Inactive')}\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.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 => )}\n \n }/>\n\n \n }\n
    \n
    \n\n
    \n \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 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 \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 \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 \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 \n this.updateTitle(e.target.value)}\n className=\"form-control\"\n id=\"user-title-input\" />\n
    \n
    \n \n this.updateEmail(e.target.value)}\n id=\"user-email-input\" />\n {e.email &&\n
    \n {e.email}\n
    \n }\n
    \n
    \n \n this.updatePhone(e.target.value)}\n className=\"form-control\"\n id=\"user-phone-input\" />\n
    \n
    \n \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 \n \n \n
    \n }\n {!this.props.new && !disabled &&\n
    \n \n \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
    \n
    \n {children}\n
    \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(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 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 \n store.changeOrganizationFilter(e)}\n isMulti={true}\n placeholder={selection_placeholder}\n id=\"organization_filter\" />\n
    \n
    \n \n store.changeUserStatusFilter(e)}\n placeholder={selection_placeholder}\n id=\"status_filter\" />\n
    \n
    \n \n store.changeAdminRoleFilter(e)}\n placeholder={selection_placeholder}\n id=\"admin_role_filter\" />\n
    \n \n
    \n \n \n
    \n
    \n
    \n
    \n \n \n
    \n store.users[id])}\n keyField=\"id\"\n HeaderRow={({Col, Row}) =>\n \n \n store.toggleBulkTargetsAll()}/>\n \n {gettext(\"User\")}\n {gettext(\"Organization\")}\n {gettext(\"Programs\")}\n {gettext(\"Admin Role\")}\n {gettext(\"Status\")}\n \n }\n Row={({Col, Row, data}) =>\n \n \n \n \n store.updateUserProfile(data.id, new_user_data)}\n onCreate={(new_user_data) => store.saveNewUser(new_user_data)}\n onCreateAndAddAnother={(new_user_data) => store.saveNewUserAndAddAnother(new_user_data)}\n organizations={store.organization_selections} />\n \n )}\n ProgramSection={observer(() =>\n \n store.saveUserPrograms(data.id, new_program_data)}/>\n \n )}\n HistorySection={observer(() =>\n \n store.resendRegistrationEmail(data.id)}\n onSave={(new_data) => store.updateUserIsActive(data.id, new_data)}/>\n \n )}\n />\n \n }>\n \n store.toggleBulkTarget(data.id) }/>\n \n \n
    store.toggleEditingTarget(data.id)} >\n  \n {data.name || \"---\"} {data.is_super && {gettext(\"Super Admin\")}}\n
    \n \n \n  \n {data.organization_name || \"---\"}\n \n \n \n  \n {data.user_programs} {gettext(\"programs\")}\n \n \n {data.is_admin?gettext('Yes'):gettext('No')}\n {data.is_active?gettext('Active'):gettext('Inactive')}\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