Target debugging & updates

Thank you @diana for the updates on targets in the new CHT versions during the round up. I decided to post some lingering questions on the forum, given the remaining time on that call.

  1. Are there any built in ways to quickly debug targets? Maybe through console, similar to how window.CHTCore.debugFormModel() is used for a form. At the moment we’ve created a “hidden” task to print out general info such as “user”, and use a print method that checks if a can_debug_targets permission has been granted in order to output various pieces of info to the console.
    Debug task:
{
    id: 'debug',
    icon: 'debug',
    translation_key: 'targets.debug',
    type: 'count',
    goal: -1,
    date: 'reported',
    appliesTo: 'contacts',
    appliesToType: ['indawo'], // For a CHW this will only fire once since it's the top-most place
    context: 'false', // We don't want this to display a block
    appliesIf: passthrough(
      () => false, // Should never apply
      ['Target: ', '[General] debug info'],
      ['User:', () => user],
    )
  },

Print logic:

{
    id: 'dwelling-registrations-weekly',
    icon: 'wcg-dwelling',
    translation_key: 'targets.dwelling.registration.weekly.count.title',
    type: 'count',
    goal: -1,
    date: 'reported',
    appliesTo: 'contacts',
    appliesToType: ['dwelling'],
    context: 'user.role === "chw" || user.contact_type === "chw"',
    appliesIf: passthrough(
      ({ contact: { reported_date, visit_date } }) => 
        visit_date ? isISOWithinWeek(visit_date) : isMilliWithinWeek(reported_date),
      ['Target: ', '[Weekly] Dwelling registration'],
      ['Reported date:', ({ contact: { reported_date } }) => reported_date],
      ['Visit date:', ({ contact: { visit_date } }) => visit_date]
    )
  },
...
const passthrough = (func, ...logArgs) => (...args) => {
  if (hasDebugPermission()) {
    for (const logArg of logArgs) {
      print(...logArg.map(arg => (typeof arg === 'function' ? arg(...args) : arg)));
    }
  }
  return func(...args);
};

// We're doing this because the 'cht' variable is only available in function target function calls, not globally
let _canDebugTargets;
function hasDebugPermission(){
  // eslint-disable-next-line eqeqeq
  if(_canDebugTargets == null){
    // The current role is used by default
    // https://docs.communityhealthtoolkit.org/building/targets/targets-js/#cht-api
    _canDebugTargets = cht.v1.hasPermissions('can_debug_targets');
  }
  return _canDebugTargets;
}

function print(...args) {
  console.log(...args);
}
  1. Is there an appetite to have “weekly” targets? Speaking under correction, we still only have “monthly” and “all” - with the option to provide further fine tuning through the appliesIf. Just wondering if anyone else requires “weekly” as an easy config option, and if that’s something CHT plans to implement.
    Related to this thread:
    Displaying targets weekly - Technical Support - Community Health Toolkit

  2. Why does the “context” prop take a js string and not a function? In our case, most of our targets are, essentially, duplicated. Each would show up as a weekly and a monthly target for either a CHW or an OTL. What this means is that we define the same string in multiple places, where a function or variable could have been referenced - making it easy to change in a single place.

To add a bit more context, we recently had a user that for some reason had no ‘role’ property on their login linked hierarchy CHW, this resulted in NO target blocks showing up. Since we couldn’t replicate it locally, we had to add some sort of mechanism of enabling and obtaining debug info on our instance. After figuring out the issue, as a fallback, we added the `contact_type’ prop check on every context string.

3 Likes

Hi @Anro

Great questions!!

  1. The CHT script api is available in both tasks and targets: tasks.js | Community Health Toolkit
    I think it’s quite a smart way to use it :slight_smile:

Can you provide more details about what you would like to debug and how you see this working?

  1. I believe not, sadly. I doubt medic will implement support for weekly targets soon.

  2. Oh, the context prop haha.

I think it’s the same as the form context property, which is also a string.
This gets evaluated at render time, to either show or hide the widget, just like forms context are evaluated, by Angular.
With AngularJS there was an easy way to pass it an expression and some variables and piggyback on the view template logic to evaluate that expression and return the result (it had the same capabilities), so it was convenient to use.
When we switched to Angular, this feature was no longer “public”, and we had to kinda hack into Angular bowels to access it.

So you could say that the reason is historical. I suppose that now it would be possible to switch to a function, though I haven’t tried myself.

All the other targets and tasks code (like appliesIf and resolvesIf) and transformed by cht-conf compile and then are run through the rules-engine (the library that generates all the tasks and targets) at calculation time.

we recently had a user that for some reason had no ‘role’ property on their login linked hierarchy CHW, this resulted in NO target blocks showing up.

I see!
If it’s generic info about the user that you seek, I think there might be an easy way to make it available through a debugRulesEngineContext function, that can log the user-settings doc and the user contact doc that gets passed to the rules engine.