Skip to content

Commit

Permalink
feat(medic/cht-core#6598): Command line to convert and upload trainin…
Browse files Browse the repository at this point in the history
…g forms (#529)

Adds `convert-training-forms`, `upload-training-forms` and `validate-training-forms` commands for training forms
  • Loading branch information
latin-panda committed Mar 9, 2023
1 parent afb480a commit fb700ef
Show file tree
Hide file tree
Showing 16 changed files with 434 additions and 104 deletions.
17 changes: 17 additions & 0 deletions src/fn/convert-training-forms.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const convertForms = require('../lib/convert-forms').execute;
const environment = require('../lib/environment');
const { TRAINING_FORMS_PATH } = require('../lib/project-paths');

const convertTrainingForms = (forms) => {
return convertForms(environment.pathToProject, 'training', {
enketo: true,
forms: forms,
});
};

module.exports = {
requiresInstance: false,
convertTrainingForms,
TRAINING_FORMS_PATH,
execute: () => convertTrainingForms(environment.extraArgs)
};
17 changes: 17 additions & 0 deletions src/fn/upload-training-forms.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
const environment = require('../lib/environment');
const uploadForms = require('../lib/upload-forms').execute;
const { TRAINING_FORMS_PATH } = require('../lib/project-paths');

const uploadTrainingForms = (forms) => {
return uploadForms(environment.pathToProject, 'training', {
id_prefix: 'training:',
forms: forms,
});
};

module.exports = {
requiresInstance: true,
uploadTrainingForms,
TRAINING_FORMS_PATH,
execute: () => uploadTrainingForms(environment.extraArgs)
};
12 changes: 12 additions & 0 deletions src/fn/validate-training-forms.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const validateForms = require('../lib/validate-forms');
const environment = require('../lib/environment');

const validateTrainingForms = (forms) => {
return validateForms(environment.pathToProject, 'training', { forms });
};

module.exports = {
requiresInstance: false,
validateTrainingForms,
execute: () => validateTrainingForms(environment.extraArgs)
};
139 changes: 73 additions & 66 deletions src/fn/watch-project.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@ const watcher = require('@parcel/watcher');
const { validateAppForms } = require('./validate-app-forms');
const { validateContactForms } = require('./validate-contact-forms');
const { validateCollectForms } = require('./validate-collect-forms');
const { validateTrainingForms } = require('./validate-training-forms');
const { uploadAppForms } = require('./upload-app-forms');
const { uploadContactForms } = require('./upload-contact-forms');
const { uploadCollectForms } = require('./upload-collect-forms');
const { uploadTrainingForms } = require('./upload-training-forms');
const convertForms = require('../lib/convert-forms');
const uploadForms = require('../lib/upload-forms');
const { deleteForms } = require('../fn/delete-forms');
const { convertAppForms, APP_FORMS_PATH } = require('./convert-app-forms');
const { convertContactForm, CONTACT_FORMS_PATH } = require('./convert-contact-forms');
const { convertTrainingForms, TRAINING_FORMS_PATH } = require('./convert-training-forms');
const { convertCollectForms, COLLECT_FORMS_PATH } = require('./convert-collect-forms');
const { uploadAppSettings, APP_SETTINGS_DIR_PATH, APP_SETTINGS_JSON_PATH } = require('./upload-app-settings');
const { execute: compileAppSettings, configFileMatcher } = require('./compile-app-settings');
Expand All @@ -39,8 +42,10 @@ const uploadInitialState = async (api) => {
await uploadResources();
await runValidation(validateAppForms, environment.extraArgs);
await runValidation(validateContactForms, environment.extraArgs);
await runValidation(validateTrainingForms, environment.extraArgs);
await uploadAppForms(environment.extraArgs);
await uploadContactForms(environment.extraArgs);
await uploadTrainingForms(environment.extraArgs);
await uploadCustomTranslations();
await uploadAppSettings(api);
};
Expand Down Expand Up @@ -87,87 +92,99 @@ const deleteForm = (fileName, formDir) => {
return false;
};

const processAppForm = (eventType, fileName) => {
if (eventType === watcherEvents.DeleteEvent && deleteForm(fileName, APP_FORMS_PATH)) {
return true;
const getFormCommandContext = (parsedPath) => {
if (parsedPath.dir === path.join(environment.pathToProject, APP_FORMS_PATH)) {
return {
path: APP_FORMS_PATH,
validateForms: validateAppForms,
uploadForms: uploadAppForms,
convertForms: convertAppForms,
};
}
let form = uploadForms.formFileMatcher(fileName);
if (form) {
eventQueue.enqueue(async () => {
await runValidation(validateAppForms, [form]);
await uploadAppForms([form]);
return fileName;
});
return true;

if (parsedPath.dir === path.join(environment.pathToProject, TRAINING_FORMS_PATH)) {
return {
path: TRAINING_FORMS_PATH,
validateForms: validateTrainingForms,
uploadForms: uploadTrainingForms,
convertForms: convertTrainingForms,
};
}

form = convertForms.formFileMatcher(fileName);
if (form) {
eventQueue.enqueue(async () => {
await convertAppForms([form]);
return fileName;
});
return true;
if (parsedPath.dir === path.join(environment.pathToProject, CONTACT_FORMS_PATH)) {
return {
path: CONTACT_FORMS_PATH,
validateForms: validateContactForms,
uploadForms: uploadContactForms,
convertForms: convertContactForm,
};
}
return false;
};

const processAppFormMedia = (formMediaDir, fileName) => {
const form = uploadForms.formMediaMatcher(formMediaDir);
if (form) {
eventQueue.enqueue(async () => {
await runValidation(validateAppForms,[form]);
await uploadAppForms([form]);
return fileName;
});
return true;
if (parsedPath.dir === path.join(environment.pathToProject, COLLECT_FORMS_PATH)) {
return {
path: COLLECT_FORMS_PATH,
validateForms: validateCollectForms,
uploadForms: uploadCollectForms,
convertForms: convertCollectForms,
};
}
return false;

return;
};

const processContactForm = (eventType, fileName) => {
if (eventType === watcherEvents.DeleteEvent && deleteForm(fileName, CONTACT_FORMS_PATH)) {
const processForm = (eventType, fileName, commandContext) => {
if (eventType === watcherEvents.DeleteEvent && deleteForm(fileName, commandContext.path)) {
return true;
}
let form = convertForms.formFileMatcher(fileName);
let form = uploadForms.formFileMatcher(fileName);
if (form) {
eventQueue.enqueue(async () => {
await convertContactForm([form]);
await runValidation(commandContext.validateForms, [form]);
await commandContext.uploadForms([form]);
return fileName;
});
return true;
}

form = uploadForms.formFileMatcher(fileName);
form = convertForms.formFileMatcher(fileName);
if (form) {
eventQueue.enqueue(async () => {
await runValidation(validateContactForms,[form]);
await uploadContactForms([form]);
await commandContext.convertForms([form]);
return fileName;
});
return true;
}
return false;
};

const processCollectForm = (eventType, fileName) => {
if (eventType === watcherEvents.DeleteEvent && deleteForm(fileName, COLLECT_FORMS_PATH)) {
return true;
const getFormMediaCommandContext = (parsedPath) => {
if (parsedPath.dir.startsWith(path.join(environment.pathToProject, APP_FORMS_PATH))
&& path.parse(parsedPath.dir).dir.endsWith(APP_FORMS_PATH)) {
// Check if the directory's immediate parent is forms/app
return {
validateForms: validateAppForms,
uploadForms: uploadAppForms,
};
}
let form = uploadForms.formFileMatcher(fileName);
if (form) {
eventQueue.enqueue(async () => {
await runValidation(validateCollectForms,[form]);
await uploadCollectForms([form]);
return fileName;
});
return true;

if (parsedPath.dir.startsWith(path.join(environment.pathToProject, TRAINING_FORMS_PATH))
&& path.parse(parsedPath.dir).dir.endsWith(TRAINING_FORMS_PATH)) {
// Check if the directory's immediate parent is forms/training
return {
validateForms: validateTrainingForms,
uploadForms: uploadTrainingForms,
};
}

form = convertForms.formFileMatcher(fileName);
return;
};

const processFormMedia = (formMediaDir, fileName, commandContext) => {
const form = uploadForms.formMediaMatcher(formMediaDir);
if (form) {
eventQueue.enqueue(async () => {
await convertCollectForms([form]);
await runValidation(commandContext.validateForms,[form]);
await commandContext.uploadForms([form]);
return fileName;
});
return true;
Expand Down Expand Up @@ -212,29 +229,19 @@ const watchProject = {
const parsedPath = path.parse(changePath);
const fileName = parsedPath.base;

if (parsedPath.dir === path.join(environment.pathToProject, APP_FORMS_PATH)) {
processAppForm(event.type, fileName);
const formContext = getFormCommandContext(parsedPath);
if (formContext) {
processForm(event.type, fileName, formContext);
continue;
}

if (parsedPath.dir.startsWith(path.join(environment.pathToProject, APP_FORMS_PATH))
&& path.parse(parsedPath.dir).dir.endsWith(APP_FORMS_PATH)) { // check if the directory's immediate parent is forms/app
const formMediaContext = getFormMediaCommandContext(parsedPath);
if (formMediaContext) {
const dirName = path.parse(parsedPath.dir).base;
processAppFormMedia(dirName, fileName);
processFormMedia(dirName, fileName, formMediaContext);
continue;
}

if (parsedPath.dir === path.join(environment.pathToProject, CONTACT_FORMS_PATH)) {
processContactForm(event.type, fileName);
continue;
}

if (parsedPath.dir === path.join(environment.pathToProject, COLLECT_FORMS_PATH)) {
processCollectForm(event.type, fileName);
continue;
}


if (parsedPath.dir === path.join(environment.pathToProject, TRANSLATIONS_DIR_PATH)) {
eventQueue.enqueue(async () => {
await uploadCustomTranslations();
Expand Down
10 changes: 9 additions & 1 deletion src/lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,17 @@ const defaultActions = [
'convert-app-forms',
'convert-collect-forms',
'convert-contact-forms',
'convert-training-forms',
'validate-app-forms',
'validate-collect-forms',
'validate-contact-forms',
'validate-training-forms',
'backup-all-forms',
'delete-all-forms',
'upload-app-forms',
'upload-collect-forms',
'upload-contact-forms',
'upload-training-forms',
'upload-resources',
'upload-branding',
'upload-partners',
Expand All @@ -41,12 +44,15 @@ const defaultArchiveActions = [
'convert-app-forms',
'convert-collect-forms',
'convert-contact-forms',
'convert-training-forms',
'validate-app-forms',
'validate-collect-forms',
'validate-contact-forms',
'validate-training-forms',
'upload-app-forms',
'upload-collect-forms',
'upload-contact-forms',
'upload-training-forms',
'upload-resources',
'upload-branding',
'upload-partners',
Expand Down Expand Up @@ -148,7 +154,8 @@ module.exports = async (argv, env) => {
const validateActions = [
'validate-app-forms',
'validate-collect-forms',
'validate-contact-forms'
'validate-contact-forms',
'validate-training-forms',
];
actions = actions.filter(action => !validateActions.includes(action));
} else {
Expand All @@ -161,6 +168,7 @@ module.exports = async (argv, env) => {
addFormValidationIfNecessary('app');
addFormValidationIfNecessary('collect');
addFormValidationIfNecessary('contact');
addFormValidationIfNecessary('training');
}

actions = actions.map(actionName => {
Expand Down
1 change: 1 addition & 0 deletions src/lib/project-paths.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ module.exports = {
APP_FORMS_PATH: path.join('forms', 'app'),
CONTACT_FORMS_PATH: path.join('forms', 'contact'),
COLLECT_FORMS_PATH: path.join('forms', 'collect'),
TRAINING_FORMS_PATH: path.join('forms', 'training'),
TRANSLATIONS_DIR_PATH: 'translations',
RESOURCE_CONFIG_PATH: 'resources.json',
RESOURCES_DIR_PATH: 'resources'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<?xml version="1.0"?>
<h:html xmlns="http://www.w3.org/2002/xforms" xmlns:h="http://www.w3.org/1999/xhtml" xmlns:ev="http://www.w3.org/2001/xml-events" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:jr="http://openrosa.org/javarosa" xmlns:orx="http://openrosa.org/xforms">
<h:head>
<h:title>new_actions_training</h:title>
<model>
<itext>
<translation lang="en">
<text id="/new_actions_training/action_icons/action_icons_note_1:label">
<value>The "New Action" icon at the bottom of your app has changed to a big blue plus icon.</value>
</text>
<text id="/new_actions_training/ending/ending_note_1:label">
<value>If you do not understand these changes, please contact your supervisor.</value>
</text>
<text id="/new_actions_training/ending/ending_note_2:label">
<value>When you're ready, go ahead and start using your app.</value>
</text>
<text id="/new_actions_training/intro/intro_note_1:label">
<value>There have been some changes to icons in your app. The next few screens will show you the difference.</value>
</text>
<text id="/new_actions_training/intro/intro_note_2:label">
<value>Read each screen carefully and tap "Next" if you understand. If you need extra support, please contact your supervisor.</value>
</text>
</translation>
</itext>
<instance>
<new_actions_training id="new_actions_training" prefix="J1!new_actions_training!" delimiter="#" version="2023-01-18 04:35:53">
<intro tag="hidden">
<intro_note_1 tag="hidden"/>
<intro_note_2 tag="hidden"/>
</intro>
<action_icons tag="hidden">
<action_icons_note_1 tag="hidden"/>
</action_icons>
<ending tag="hidden">
<ending_note_1 tag="hidden"/>
<ending_note_2 tag="hidden"/>
</ending>
<meta tag="hidden">
<instanceID/>
</meta>
</new_actions_training>
</instance>
<bind nodeset="/new_actions_training/intro/intro_note_1" readonly="true()" type="string"/>
<bind nodeset="/new_actions_training/intro/intro_note_2" readonly="true()" type="string"/>
<bind nodeset="/new_actions_training/action_icons/action_icons_note_1" readonly="true()" type="string"/>
<bind nodeset="/new_actions_training/ending/ending_note_1" readonly="true()" type="string"/>
<bind nodeset="/new_actions_training/ending/ending_note_2" readonly="true()" type="string"/>
<bind nodeset="/new_actions_training/meta/instanceID" type="string" readonly="true()" calculate="concat('uuid:', uuid())"/>
</model>
</h:head>
<h:body class="pages">
<group appearance="field-list" ref="/new_actions_training/intro">
<input ref="/new_actions_training/intro/intro_note_1">
<label ref="jr:itext('/new_actions_training/intro/intro_note_1:label')"/>
</input>
<input ref="/new_actions_training/intro/intro_note_2">
<label ref="jr:itext('/new_actions_training/intro/intro_note_2:label')"/>
</input>
</group>
<group appearance="field-list" ref="/new_actions_training/action_icons">
<input ref="/new_actions_training/action_icons/action_icons_note_1">
<label ref="jr:itext('/new_actions_training/action_icons/action_icons_note_1:label')"/>
</input>
</group>
<group appearance="field-list" ref="/new_actions_training/ending">
<input ref="/new_actions_training/ending/ending_note_1">
<label ref="jr:itext('/new_actions_training/ending/ending_note_1:label')"/>
</input>
<input ref="/new_actions_training/ending/ending_note_2">
<label ref="jr:itext('/new_actions_training/ending/ending_note_2:label')"/>
</input>
</group>
</h:body>
</h:html>
Binary file not shown.
Empty file.
Empty file.
Loading

0 comments on commit fb700ef

Please sign in to comment.