From f11129695fd3e049e41d1d60fb1b574c1e047e49 Mon Sep 17 00:00:00 2001 From: jomcarvajal Date: Wed, 10 Sep 2025 19:27:34 -0600 Subject: [PATCH 1/6] feat(#383): improvements in Building App Forms page --- content/en/building/tutorials/app-forms.md | 146 +++++++++++++-------- layouts/shortcodes/copytable.html | 69 ++++++++++ 2 files changed, 163 insertions(+), 52 deletions(-) create mode 100644 layouts/shortcodes/copytable.html diff --git a/content/en/building/tutorials/app-forms.md b/content/en/building/tutorials/app-forms.md index 04ee3c958f..9d91c7805a 100644 --- a/content/en/building/tutorials/app-forms.md +++ b/content/en/building/tutorials/app-forms.md @@ -15,6 +15,48 @@ aliases: - /apps/tutorials/app-forms --- + + App forms allow users to submit reports from Android devices. This tutorial will take you through how to build App forms for CHT applications, including: @@ -39,70 +81,70 @@ You should have a [functioning CHT instance with `cht-conf` installed locally]({ ## Implementation Steps -Create a new spread sheet in Google sheets or other preferred editor like Excel or Open Office. Name the spreadsheet `assessment`. The final file name should be `assessment.xlsx`. +Create a new spread sheet in [Google Sheets](https://workspace.google.com/products/sheets/) or other preferred editor like [Excel](https://www.microsoft.com/en-us/microsoft-365/excel) or [LibreOffice](https://www.libreoffice.org/). Name the spreadsheet `assessment`. The final file name should be `assessment.xlsx`. Create 2 additional sheets. Rename the sheets `survey`, `choices` and `settings`. ### 1. Define XLS Survey/Form Fields -Create the following columns in the survey sheet and then add the following rows that are populated automatically before the form is rendered to the user. These fields are usually hidden by default but can be accessed to display certain information about the person being assessed: - -| type | name | label | required | relevant | appearance | constraint | constraint_message | calculation | choice_filter | hint | default | -|-------------| --------------- | --------------------------- | -------- | ----------------- |------------| ---------- | ------------------- | ---------------------- | -------------- | ----------------------------- | ------- | -| begin group | inputs | Patient | | ./source = 'user' | field-list | | | | | | | -| hidden | source | Source | | | | | | | | | user | -| hidden | source_id | Source_ID | | | | | | | | | | -| hidden | task_id | Task_ID | | | | | | | | | | -| begin group | contact | Contact | | | | | | | | | | -| string | _id | Patient ID | | | select-contact type-person | | | | | Select a person from the list | | -| hidden | patient_id | Medic ID | | | | | | | | | | -| hidden | name | Patient Name | | | | | | | | | | -| begin group | parent | Parent | | | | | | | | | | -| hidden | _id | Family UUID | | | | | | | | | | -| begin group | parent | Grandparent | | | | | | | | | | -| hidden | _id | CHW Area UUID | | | | | | | | | | -| hidden | name | CHW Name | | | | | | | | | | -| hidden | phone | CHW Phone | | | | | | | | | | -| begin group | parent | Great Grandparent | | | | | | | | | | -| hidden | _id | CU UUID | | | | | | | | | | -| end group | | | | | | | | | | | | -| end group | | | | | | | | | | | | -| end group | | | | | | | | | | | | -| end group | | | | | | | | | | | | -| end group | | | | | | | | | | | | -| calculate | patient_id | | | | | | | ../inputs/contact/_id | | | | -| calculate | patient_name | | | | | | | ../inputs/contact/name | | | | - - -Add the following rows that define the data collection fields below the existing rows (leave out the column names): - -| type | name | label | required | relevant | appearance | constraint | constraint_message | calculation | choice_filter | hint | default | -| ----------------------------- | ----------------- | ---------------------------------- | -------- | ------------------- | ---------- | ---------- | ------------------- | ----------- | -------------- | ---- | ------- | -| begin group | group_assessment | Assessment | | | | | | | | | | -| select_one yes_no | cough | Does ${patient_name} have a cough? | yes | | | | | | | | | -| select_one symptom_duration | cough_duration | How long has the cough lasted? | yes | ${cough} = 'yes' | | | | | | | | -| end group | | | | | | | | | | | | +Copy everything inside the code block below, then paste into cell A1 of a new sheet named `survey` in Excel or Google Sheets: + +{{< copytable id="survey" label="Copy survey sheet" >}} +type name label required relevant appearance constraint constraint_message calculation choice_filter hint default +begin group inputs Patient ./source = 'user' field-list +hidden source Source user +hidden source_id Source_ID +hidden task_id Task_ID +begin group contact Contact +string _id Patient ID select-contact type-person Select a person from the list +hidden patient_id Medic ID +hidden name Patient Name +begin group parent Parent +hidden _id Family UUID +begin group parent Grandparent +hidden _id CHW Area UUID +hidden name CHW Name +hidden phone CHW Phone +begin group parent Great Grandparent +hidden _id CU UUID +end group +end group +end group +end group +end group +calculate patient_id ../inputs/contact/_id +calculate patient_name ../inputs/contact/name +begin group group_assessment Assessment +select_one yes_no cough Does ${patient_name} have a cough? yes +select_one symptom_duration cough_duration How long has the cough lasted? yes ${cough} = 'yes' +select_one yes_no fever Does ${patient_name} have a fever? yes +select_one yes_no diarrhea Does ${patient_name} have diarrhea? yes +end group +end group +{{< /copytable >}} ### 2. Define the Choices -Add the following column names and rows to the choices sheet: +Copy everything inside the code block below, then paste into cell A1 of a new sheet named `choices`: -| list_name | name | label | -| ----------------- | ---- | --------------- | -| yes_no | yes | Yes | -| yes_no | no | No | -| symptom_duration | 3 | 3 days or less | -| symptom_duration | 7 | 4 - 7 days | -| symptom_duration | 13 | 8 - 13 days | -| symptom_duration | 14 | 14 days or more | +{{< copytable id="choices" label="Copy choices sheet" >}} +list_name name label +yes_no yes Yes +yes_no no No +symptom_duration 3 3 days or less +symptom_duration 7 4 - 7 days +symptom_duration 13 8 - 13 days +symptom_duration 14 14 days or more +{{< /copytable >}} ### 3. Define the XLS Settings -Add the following column names and rows to the settings sheet: +Copy everything inside the code block below, then paste into cell A1 of a new sheet named `settings`: -| form_title | form_id | version | style | path | instance_name | default_language | -| -------------- | ---------- | ------- | ----- | ---- | -------------- | ----------------- | -| Assess patient | assessment | 1 | pages | data | | en | +{{< copytable id="settings" label="Copy settings sheet" >}} +form_title form_id version style path instance_name default_language +Assess patient assessment 1 pages data en +{{< /copytable >}} ### 4. Convert the XLSForm and Upload the XForm @@ -126,4 +168,4 @@ cht --url=https://:@localhost --accept-self-signed-certs con ## Next steps -In the next tutorial, you will define the form `.properties.json` which will allow you to define the form’s title and icon, as well as when and where the form should be available. +- *[Setting Form Properties]({{< ref "building/forms/form-properties/" >}})* diff --git a/layouts/shortcodes/copytable.html b/layouts/shortcodes/copytable.html new file mode 100644 index 0000000000..0d31e2ae82 --- /dev/null +++ b/layouts/shortcodes/copytable.html @@ -0,0 +1,69 @@ + +{{ $id := .Get "id" | default (now.UnixNano) }} +{{ $tsv := .Inner | safeHTML }} +
+ +Copied! +{{/* Render visual table for user, but keep
 for copy-paste */}}
+{{ $lines := split $tsv "\n" }}
+
+  {{ range $i, $line := $lines }}
+    {{ if ne (len (trim $line " ")) 0 }}
+    
+      {{ range (split $line "\t") }}
+        {{ if eq $i 0 }}{{ else }}{{ end }}
+      {{ end }}
+    
+    {{ end }}
+  {{ end }}
+
{{ . }}{{ . }}
+ From fccd3601bfe02d455a6f3d430fccb7614bb8887e Mon Sep 17 00:00:00 2001 From: jomcarvajal Date: Wed, 10 Sep 2025 19:31:36 -0600 Subject: [PATCH 2/6] feat(#383): remove unused styles --- content/en/building/tutorials/app-forms.md | 42 ---------------------- 1 file changed, 42 deletions(-) diff --git a/content/en/building/tutorials/app-forms.md b/content/en/building/tutorials/app-forms.md index 9d91c7805a..34942fdf45 100644 --- a/content/en/building/tutorials/app-forms.md +++ b/content/en/building/tutorials/app-forms.md @@ -15,48 +15,6 @@ aliases: - /apps/tutorials/app-forms --- - - App forms allow users to submit reports from Android devices. This tutorial will take you through how to build App forms for CHT applications, including: From 69349e2a75658c142d8b1eb3ec2c81f652164864 Mon Sep 17 00:00:00 2001 From: jomcarvajal Date: Thu, 11 Sep 2025 06:22:46 -0600 Subject: [PATCH 3/6] feat(#383): add more description to step 1 --- content/en/building/tutorials/app-forms.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/content/en/building/tutorials/app-forms.md b/content/en/building/tutorials/app-forms.md index 34942fdf45..800e86ba98 100644 --- a/content/en/building/tutorials/app-forms.md +++ b/content/en/building/tutorials/app-forms.md @@ -45,7 +45,9 @@ Create 2 additional sheets. Rename the sheets `survey`, `choices` and `settings` ### 1. Define XLS Survey/Form Fields -Copy everything inside the code block below, then paste into cell A1 of a new sheet named `survey` in Excel or Google Sheets: +This rows are populated automatically before the form is rendered to the user. These fields are usually hidden by default but can be accessed to display certain information about the person being assessed. + +Copy everything inside the table below, then paste into cell A1 of a new sheet named `survey` in Google Sheets or your prefered editor: {{< copytable id="survey" label="Copy survey sheet" >}} type name label required relevant appearance constraint constraint_message calculation choice_filter hint default @@ -83,7 +85,7 @@ end group ### 2. Define the Choices -Copy everything inside the code block below, then paste into cell A1 of a new sheet named `choices`: +Copy everything inside the table below, then paste into cell A1 of a new sheet named `choices`: {{< copytable id="choices" label="Copy choices sheet" >}} list_name name label @@ -97,7 +99,7 @@ symptom_duration 14 14 days or more ### 3. Define the XLS Settings -Copy everything inside the code block below, then paste into cell A1 of a new sheet named `settings`: +Copy everything inside the table below, then paste into cell A1 of a new sheet named `settings`: {{< copytable id="settings" label="Copy settings sheet" >}} form_title form_id version style path instance_name default_language From 6e8f3f143dc6f59eb0f1fbfb43af673bdf60e7c6 Mon Sep 17 00:00:00 2001 From: jomcarvajal Date: Thu, 25 Sep 2025 19:40:16 -0600 Subject: [PATCH 4/6] feat(#383): update button styles, add new notes for style-guide --- content/en/building/tutorials/app-forms.md | 6 +-- .../contributing/docs/style-guide.md | 33 ++++++++++++++++ .../{copytable.html => copy-table.html} | 38 +++++++++++++++---- 3 files changed, 66 insertions(+), 11 deletions(-) rename layouts/shortcodes/{copytable.html => copy-table.html} (72%) diff --git a/content/en/building/tutorials/app-forms.md b/content/en/building/tutorials/app-forms.md index 800e86ba98..59373b2cf6 100644 --- a/content/en/building/tutorials/app-forms.md +++ b/content/en/building/tutorials/app-forms.md @@ -47,7 +47,7 @@ Create 2 additional sheets. Rename the sheets `survey`, `choices` and `settings` This rows are populated automatically before the form is rendered to the user. These fields are usually hidden by default but can be accessed to display certain information about the person being assessed. -Copy everything inside the table below, then paste into cell A1 of a new sheet named `survey` in Google Sheets or your prefered editor: +Copy everything inside the table below by clicking the "πŸ“‹ Copy survey sheet" button, then paste into cell A1 of a new sheet named `survey` in Google Sheets or your prefered editor: {{< copytable id="survey" label="Copy survey sheet" >}} type name label required relevant appearance constraint constraint_message calculation choice_filter hint default @@ -85,7 +85,7 @@ end group ### 2. Define the Choices -Copy everything inside the table below, then paste into cell A1 of a new sheet named `choices`: +Copy everything inside the table below by clicking the "πŸ“‹ Copy choices sheet" button, then paste into cell A1 of a new sheet named `choices` in Google Sheets or your prefered editor: {{< copytable id="choices" label="Copy choices sheet" >}} list_name name label @@ -99,7 +99,7 @@ symptom_duration 14 14 days or more ### 3. Define the XLS Settings -Copy everything inside the table below, then paste into cell A1 of a new sheet named `settings`: +Copy everything inside the table below by clicking the "πŸ“‹ Copy settings sheet" button, then paste into cell A1 of a new sheet named `settings` in Google Sheets or your prefered editor: {{< copytable id="settings" label="Copy settings sheet" >}} form_title form_id version style path instance_name default_language diff --git a/content/en/community/contributing/docs/style-guide.md b/content/en/community/contributing/docs/style-guide.md index 426953a1b5..dd448d9bfb 100644 --- a/content/en/community/contributing/docs/style-guide.md +++ b/content/en/community/contributing/docs/style-guide.md @@ -191,6 +191,39 @@ To achieve this use a markdown table with the letter X (`X`) to mark events, lea > [!TIP] > The opening `{{%/* schedule */%}}` and closing `{{%/* /schedule */%}}` shortcode must come before and after the markdown table respectively in order for it to correctly style the table. +### πŸ“‹ Copy-paste-friendly Tables + +You can include a visual table in your documentation with a **"Copy table" button** that makes it easy for users to copy the table contents (as TSV – tab-separated values). This is useful for sharing structured data that users may want to paste into a spreadsheet like Google Sheets or another tool. + +Use the following shortcode format: + + {{}} + Column A Column B Column C + Value-1 A1 B1 + Value-2 A2 B2 + {{}} + +This will render: + +- A nicely styled HTML table. +- A **Copy** button above the table. +- When clicked, the button copies the table content (as plain text) to the clipboard. +- A small β€œCopied!” message briefly appears to confirm the action. + +#### βœ… Example output + +{{< copytable id="tsv" label="Copy TSV" >}} +Name Role Region +Fatou CEO Senegal +Jose Developer Costa Rica +{{}} + +#### πŸ’‘ Notes + +- The copied content uses **tab-separated values**, which work well in spreadsheets or plain text files. +- The button adapts automatically to **light and dark themes**. +- You can customize the button label with the `label` parameter (default: `"Copy table"`). + ### Grammar and punctuation in headers Use title case for page `title`, and sentence case for `linkTitle` description. Do not end titles with periods. diff --git a/layouts/shortcodes/copytable.html b/layouts/shortcodes/copy-table.html similarity index 72% rename from layouts/shortcodes/copytable.html rename to layouts/shortcodes/copy-table.html index 0d31e2ae82..b43691297d 100644 --- a/layouts/shortcodes/copytable.html +++ b/layouts/shortcodes/copy-table.html @@ -1,29 +1,51 @@