cht-conf 6.0.0 → 6.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [6.0.2](https://github.com/medic/cht-conf/compare/v6.0.1...v6.0.2) (2026-01-16)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **#787:** upload forms with correct `internalId` property ([#788](https://github.com/medic/cht-conf/issues/788)) ([3a28dce](https://github.com/medic/cht-conf/commit/3a28dce3499c7cc2aac7ad5c8a7327303288986f)), closes [#787](https://github.com/medic/cht-conf/issues/787)
7
+
8
+ ## [6.0.1](https://github.com/medic/cht-conf/compare/v6.0.0...v6.0.1) (2026-01-14)
9
+
10
+
11
+ ### Bug Fixes
12
+
13
+ * **#785:** add `xls2xform-medic.cmd` file for Windows ([2686ce5](https://github.com/medic/cht-conf/commit/2686ce54b2aafa2bfec387f285458f9d9481f2a8)), closes [#785](https://github.com/medic/cht-conf/issues/785)
14
+
1
15
  # [6.0.0](https://github.com/medic/cht-conf/compare/v5.6.0...v6.0.0) (2026-01-12)
2
16
 
3
17
 
@@ -5,11 +19,56 @@
5
19
  * feat([#613](https://github.com/medic/cht-conf/issues/613))!: uplift pyxform to `v4.0.0-medic` ([#709](https://github.com/medic/cht-conf/issues/709)) ([d78296d](https://github.com/medic/cht-conf/commit/d78296d4df7a43699a1d7a78584be4b8cc3967f9))
6
20
 
7
21
 
8
- ### BREAKING CHANGES
22
+ ## BREAKING CHANGES
23
+
24
+ ### New bundled version of pyxform
25
+
26
+ #### Local pyxform installation is no longer required
27
+
28
+ Previously, the `pyxform` utility (required for converting form `xlsx` files to the `xml` xform format for upload) needed to be manually installed in the user's environment. Now `pyxform` (version `v4.0.0-medic`) is bundled with cht-conf and installed automatically when cht-conf is installed. The user simply needs Python `3.12+` available in their environment.
9
29
 
10
- * Requires consistent naming of form internalId.
11
- * New version of pyxform is bundled with additional form
12
- verifications.
30
+ Existing cht-conf users can safely uninstall any local `pyxform` installation. cht-conf will only use the bundled instance of `pyxform`.
31
+
32
+ #### New pyxform version may require change to forms
33
+
34
+ The new version of `pyxform` brings with it a number of importiant changes that may require updating existing form `xlsx` files for compatibility. The known changes include:
35
+
36
+ ##### Modified Functionality
37
+ - Attribute ordering in the generated XML file will now be deterministic.
38
+ - Re-converting an unmodified form should not result in any changes to the form's xml file.
39
+ - When converting a modified form, the only lines that will be changed in the form xml are ones that are directly related to the changes in the xlsx.
40
+ - Question fields are now required to have a label or hint. (Previously, pyxform would just print a warning if a question did not have a label or hint.)
41
+ - If you try to convert a form with a question field with an empty label (and no hint) it will fail with an error like: `The survey element named 'world' has no label or hint. `
42
+ - For fields that should not be displayed to the user, consider using the `caluculate` type when you have a `calculation` expression or a `default` value. If the field value is not coming from the `calculation` or `default` columns, the `hidden` type can be used without a label/hint. This is particularly useful for input data fields or fields populated by the contact selector.
43
+ - Empty groups/repeats (without any child fields) now result in an error.
44
+ - Duplicate choice names now result in an error by default. However, support can be re-enabled via [the `allow_choice_duplicates` setting](https://xlsform.org/en/#choice-names).
45
+ - pyxform will now warn when there are missing translation columns for any of the languages in the form.
46
+
47
+ ##### Added functionality
48
+
49
+ - [`trigger` columns](https://docs.getodk.org/form-logic/#triggering-calculations-on-value-change) are now supported, allowing for calculations to be automatically re-evaluated when an unrelated value changes!
50
+ - You can now reference `${paths}` in _labels_ on the `choices` sheet.
51
+ - Support for [randomizing choice order](https://docs.getodk.org/form-question-types/#randomizing-choice-order) in select questions via the `randomize=true` parameter has been added.
52
+
53
+ * feat([#613](https://github.com/medic/cht-conf/issues/613))!: uplift pyxform to `v4.0.0-medic` ([#709](https://github.com/medic/cht-conf/issues/709)) ([d78296d](https://github.com/medic/cht-conf/commit/d78296d4df7a43699a1d7a78584be4b8cc3967f9))
54
+
55
+ ### Consistent naming of form identifier required
56
+
57
+ When there is a missmatch between the `form_id` in the xlsx, the _file name_ for the xml, and the `internalId` from the properties file, cht-conf will now raise an _error_ when you run the `convert-*-forms` action.
58
+
59
+ Now it is not required to specify the form identifier at all (in the `xlsx`, `xml`, or properties files). cht-conf will automatically set the form identifier based on the name of the xlsx file and the form type.
60
+
61
+ For cases where existing forms are now triggering an error:
62
+
63
+ - `contact` forms - remove any custom identifiers specified in the xlsx or properties file for `contact` forms.
64
+ - `app` forms - if a custom value (that does not match the xlsx file name) is currently specified as the `form_id` in the xlsx or the `internalId` in the properties file, the _file name_ of the form's xlsx/xml file should be updated to match the custom identifier value.
65
+ - The renamed form will be seen as a "new" form on the CHT instance (even though it will produce reports with the same `form` value). So, be sure to remove the old version of the form from the instance before renaming and re-uploading the updated form.
66
+ - Do not update the custom identifier value to match the form's _file name_. That will result in new reports being written with a different `form` value and can produce data consistancy issues.
67
+ - `training` forms - as with the `app` forms, if there is a missmatch in the identifier of a `training` form the _file name_ of the training form xlsx/xml file should be updated to match the custom identifier.
68
+ - Be sure to remove the old version of the form from the instance before renaming and re-uploading the updated form.
69
+ - Do not update the custom identifier value to match the form's _file name_. That will result in the form being treated as a totally new training and users would be prompted to redo the training even if they had previously completed it.
70
+
71
+ * feat([#537](https://github.com/medic/cht-conf/issues/537))!: error when form internalId does not match file name ([#776](https://github.com/medic/cht-conf/issues/776)) ([f921f1e](https://github.com/medic/cht-conf/commit/f921f1e1c6c0e32f8d2a6b5f00c9700eab338700))
13
72
 
14
73
  # [5.6.0](https://github.com/medic/cht-conf/compare/v5.5.0...v5.6.0) (2025-12-15)
15
74
 
@@ -0,0 +1,2 @@
1
+ @echo off
2
+ python "%~dp0xls2xform-medic" %*
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cht-conf",
3
- "version": "6.0.0",
3
+ "version": "6.0.2",
4
4
  "description": "Configure CHT deployments",
5
5
  "main": "./src/lib/main.js",
6
6
  "engines": {
@@ -127,6 +127,13 @@ module.exports = {
127
127
  readTitleFrom: xml =>
128
128
  xml.substring(xml.indexOf('<h:title>') + 9, xml.indexOf('</h:title>')),
129
129
 
130
+ /**
131
+ * Get the ID of the form
132
+ * @param {string} xml the XML string
133
+ * @returns {string}
134
+ */
135
+ readIdFrom: xml => /<model.*?>[^]*?<instance>[^]*?id="([^"]*)"[^]*?<\/instance>[^]*?<\/model>/.exec(xml)?.[1],
136
+
130
137
  /**
131
138
  * Escape whitespaces in a path.
132
139
  * @param {string} path the path string
@@ -10,7 +10,7 @@ const warnUploadOverwrite = require('./warn-upload-overwrite');
10
10
  const {
11
11
  getFormDir,
12
12
  getFormFilePaths,
13
- readTitleFrom,
13
+ readTitleFrom, readIdFrom,
14
14
  } = require('./forms-utils');
15
15
 
16
16
  const SUPPORTED_PROPERTIES = ['context', 'icon', 'title', 'xml2sms', 'subject_key', 'hidden_fields'];
@@ -59,7 +59,7 @@ const execute = async (projectDir, subDirectory, options) => {
59
59
  log.info(`Preparing form for upload: ${fileName}…`);
60
60
 
61
61
  const { baseFileName, mediaDir, xformPath, filePath } = getFormFilePaths(formsDir, fileName);
62
- const internalId = (options.id_prefix || '') + baseFileName.replaceAll('-', ':');
62
+ const baseDocId = (options.id_prefix || '') + baseFileName.replaceAll('-', ':');
63
63
 
64
64
  const mediaDirExists = fs.exists(mediaDir);
65
65
  if (!mediaDirExists) {
@@ -74,7 +74,14 @@ const execute = async (projectDir, subDirectory, options) => {
74
74
  sha256: hashSum.digest('hex'),
75
75
  };
76
76
 
77
- const docId = `form:${internalId}`;
77
+ const internalId = readIdFrom(xml);
78
+ if (internalId.replaceAll('-', ':') !== baseDocId) {
79
+ throw new Error(`The file name for the form [${baseFileName}] does not match the id in the xml [${
80
+ internalId
81
+ }]. Rename the form xlsx/xml files to match the id.`);
82
+ }
83
+
84
+ const docId = `form:${baseDocId}`;
78
85
  const doc = {
79
86
  _id: docId,
80
87
  type: 'form',