{"id":21850580,"url":"https://github.com/diogenesanalytics/parley","last_synced_at":"2025-10-08T11:30:33.149Z","repository":{"id":224262128,"uuid":"762832983","full_name":"DiogenesAnalytics/parley","owner":"DiogenesAnalytics","description":" Browser-based interview/application form. ","archived":false,"fork":false,"pushed_at":"2025-02-23T19:09:54.000Z","size":132,"stargazers_count":0,"open_issues_count":14,"forks_count":4,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-02T04:23:20.628Z","etag":null,"topics":["dynamic","form","html-form","javascript","pytest"],"latest_commit_sha":null,"homepage":"https://diogenesanalytics.com/parley/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/DiogenesAnalytics.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-02-24T20:16:09.000Z","updated_at":"2025-02-23T19:09:57.000Z","dependencies_parsed_at":"2024-02-26T23:40:59.707Z","dependency_job_id":"78869b7f-41ab-4162-80c7-c08e0c403fd9","html_url":"https://github.com/DiogenesAnalytics/parley","commit_stats":null,"previous_names":["diogenesanalytics/parley"],"tags_count":0,"template":true,"template_full_name":null,"purl":"pkg:github/DiogenesAnalytics/parley","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DiogenesAnalytics%2Fparley","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DiogenesAnalytics%2Fparley/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DiogenesAnalytics%2Fparley/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DiogenesAnalytics%2Fparley/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/DiogenesAnalytics","download_url":"https://codeload.github.com/DiogenesAnalytics/parley/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/DiogenesAnalytics%2Fparley/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278933978,"owners_count":26071329,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dynamic","form","html-form","javascript","pytest"],"created_at":"2024-11-28T00:18:14.632Z","updated_at":"2025-10-08T11:30:33.143Z","avatar_url":"https://github.com/DiogenesAnalytics.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![tests](https://github.com/DiogenesAnalytics/parley/actions/workflows/tests.yml/badge.svg)](https://github.com/DiogenesAnalytics/parley/actions/workflows/tests.yml)\n[![docker](https://github.com/DiogenesAnalytics/parley/actions/workflows/docker-publish.yml/badge.svg)](https://github.com/DiogenesAnalytics/parley/actions/workflows/docker-publish.yml)\n[![pages-build-deployment](https://github.com/DiogenesAnalytics/parley/actions/workflows/pages/pages-build-deployment/badge.svg)](https://github.com/DiogenesAnalytics/parley/actions/workflows/pages/pages-build-deployment)\n\n# Parley\n*(noun)*\n\n**Pronunciation:** /ˈpɑːrli/\n\n**Definition:**\nA formal discussion or negotiation between parties, especially enemies, typically to\nresolve a conflict or dispute peacefully. It often implies a temporary truce or\ncessation of hostilities to facilitate dialogue.\n\n**Example Sentence:**\nThe warring factions agreed to a parley at the neutral ground to seek a diplomatic\nsolution to their long-standing conflict.\n\n## Introduction\nThe motivation behind this software is simple: to develop a completely static\n**HTML Form** that can be deployed anywhere (including on **GitHub Pages**), to allow\nfor simple *configuration* (i.e. no need to edit the **web source** directly) using\na **JSON** file (`config.json`), and for the software to be **RIGOROUSLY** tested\n(using `pytest`) to prove the features work. That is what `Parley` is about: a\n_\"once for all\"_ solution for those who need a *simple*, *testable*, and *stable*\n*form solution* **now**.\n\n## Features\nHere we will attempt to list all the features that are *available* and *tested* in the\nsoftware:\n\n+ **configuration through JSON**: the website is meant to be configured/customized\n  through the `config.json` file (see below).\n\n+ **HTML in configurable text**: all text meant to be *configured* through the\n  `config.json` file work with **HTML** tags (including `instructions`, and\n  `question` labels):\n  ```JSON\n  {\n    \"instructions\": \"\u003ci\u003eAll\u003c/i\u003e work and \u003cb\u003eNO\u003c/b\u003e play make Jack a dull boy.\",\n  }\n  ```\n\n+ **multiline strings with arrays**: all text meant to be *configured* through the\n  `config.json` file can be of type *string* or type *array* (i.e. `instructions`, and\n  `question` labels):\n  ```JSON\n  {\n    \"questions\": [\n      {\n        \"label\": [\n          \"This is a very long question that could span multiple lines and easily\",\n          \"extend off the page. It can also have an\",\n          \"\u003ca href='https://developer.mozilla.org/en-US/docs/Web/HTML'\u003eHTML Link\u003c/a\u003e\",\n          \"embedded into it as mentioned in the previous feature explanation.\",\n          \"You can easily write LONG LONG questions and style or add links to the\",\n          \"questions using \u003cb\u003eHTML syntax\u003c/b\u003e.\"\n        ],\n        \"name\": \"message\",\n        \"type\": \"textarea\",\n        \"required\": true\n      }\n    ]\n  }\n  ```\n\n+ **custom usage instructions**: the *instructions* for using the form have been made\n  configurable through the `config.json` file, allowing for a custom usage message to\n  be supplied to the client.\n\n+ **email in usage instructions** by adding **HTML tag** with the `class` property set\n  to `email-placeholder` placeholder, your *email* will be extracted from the\n  `config.json` file and rendered into the text:\n  ```HTML\n  Send form to: \u003cstrong class='email-placeholder'\u003e[Email Address]\u003c/strong\u003e.\n  ```\n\n## Usage\nHere we outline the `Parley` software's *intended* use. Specifically we will go over\nthe `config.json` schema and what is *supported* vs. *disallowed*.\n\n### Configuration\nBelow is a minimal *configuration* of the `Parley` software:\n```JSON\n{\n  \"instructions\": \"Your custom form usage instructions\",\n  \"subject\": \"Your Form Subject\",\n  \"title\": \"Your Custom Title\",\n  \"send_button_text\": \"Custom Submit Text\",\n  \"download_button_text\": \"Custom Download Text\",\n  \"missing_field_message\": \"Custom Missing Field Alert Message\",\n  \"enable_form_download\": true,\n  \"form_backend_url\": null,\n  \"ignore_file_upload\": false,\n  \"email\": \"your_email@example.com\",\n  \"questions\": [\n    {\n      \"label\": \"Message\",\n      \"name\": \"message\",\n      \"type\": \"textarea\",\n      \"required\": true\n    }\n  ]\n}\n```\nThe above *example config* file is written in **JSON**, and each *attribute* will be\nexplained below in more detail (**NOTE**: attributes with a __*__ mark are\n**required**):\n\n+ `instructions`: The (**optional**) custom form usage instructions.\n+ `subject`(__*__): The *email subject* that will be submitted by the form.\n+ `title`(__*__): The text that will be set in the **title** element.\n+ `send_button_text`: Set custom text for send button (**optional**).\n+ `download_button_text`: Set custom text for download buttin (**optional**).\n+ `missing_field_message`: Set custom missing field alert text (**optional**).\n+ `enable_form_download`: Allow form to be downloaded (**optional**).\n+ `form_backend_url`: The (**optional**) form backend URL for submitting forms to.\n+ `ignore_file_upload`: When true files will not be uploaded (**optional**).\n+ `email`: The (**optional**) email used by the **mailto** attribute and used in the\n  *instructions* above the form.\n+ `questions`(__*__): The questions used to dynamically populate the form.\n  + `label`(__*__): The actual *question* text placed above the form input field.\n  + `name`(__*__): The *variable* name used as the _\"key\"_  in the\n    *form submission query string*.\n  + `type`(__*__): The type of input to expect from the user (discussed below).\n  + `required`(__*__): Questions with this value set to **true** must be answered\n    before form will submit.\n\n#### Basic Input Types\nAs discussed above, there are a few different *input types* currently available. These\nare listed below:\n\n+ `date`\n+ `datetime-local`\n+ `email`\n+ `file`\n+ `number`\n+ `selectbox`\n+ `tel`\n+ `text`\n+ `textarea`\n+ `time`\n+ `url`\n\nInformation describing these types can be found in the **MDN Input Element Docs**,[^1]\nexcept for `selectbox` and `textarea` which are custom *input types*.\n\n#### Custom Input Types\nWhile setting the *input type* to `textarea` simply allows you to use a\n*textarea element* (as opposed to an *input* element of type `text`), setting the\n*input type* to `selectbox` is a little more interesting:\n```JSON\n{\n  \"subject\": \"Your Form Subject\",\n  \"title\": \"Your Custom Title\",\n  \"form_backend_url\": null,\n  \"email\": \"your_email@example.com\",\n  \"questions\": [\n    {\n      \"label\": \"Select your country\",\n      \"name\": \"country\",\n      \"type\": \"selectbox\",\n      \"required\": true,\n      \"options\": [\n        {\"label\": \"--Select--\", \"value\": \"\", \"selected\": true, \"disabled\": true},\n        {\"label\": \"USA\", \"value\": \"USA\"},\n        {\"label\": \"Canada\", \"value\": \"CAN\"},\n        {\"label\": \"United Kingdom\", \"value\": \"UK\"},\n        {\"label\": \"Australia\", \"value\": \"AUS\"}\n      ],\n      \"custom\": {\n        \"multiple\": true\n      }\n    }\n  ]\n}\n```\nWhen using the `selectbox` input type, you now have access to the `options` attribute,\nwhere you can set the different options that will be _\"selectable\"_ by the user. Each\noption has 4 possible *attributes* (**NOTE**: attributes with a __*__ mark are\n**required**):\n\n+ `label`(__*__): The text displayed to the user in the **selectbox**.\n+ `value`(__*__): The text sent upon *form submission* in the _\"query string\"_.  \n+ `selected`: A *boolean* value that initializes this option as *selected* by default.\n+ `disabled`: A *boolean* value that prohibits the user from selecting this option.\n\nWhile you can set the `options` attribute in the `config.json` file for a question\n**without** setting the type to `selectbox`, nothing will happen but the website should\nfunction normally.\n\n### Additional Attributes\nYou will notice in the above section the presence of a `custom` attribute:\n```JSON\n{\n  \"custom\": {\n    \"multiple\": true\n  }\n}\n```\nThe role of this *attribute* is to configure **ANY** additional attributes related to\nthe *form input element* you are using for your _\"question.\"_ In this case we are\nsetting the **multiple** attribute to **true** for the **select** element (so that the\nuser can select multiple options in the **selectbox**).\n\n## Development\nHere we introduce the various tools related to *developing* the `Parley`\nsoftware.\n\n### Make\nA `Makefile` is available in the project root, and implements several commands to\nmake the *development process* easier. All *commands*  are executed by the following\nformat: `make [COMMAND]`. To see the *contents* of a command that will be executed upon\ninvocation of the command, simply run `make -n [COMMAND]` (**NOTE**: this serves as a\ngood way to test a command and see what **exactly** will be executed before running the\ncommand). Below is the list of the commands and their short descriptions:\n\n+ `check-docker`: check Docker and host dependencies\n+ `check-image`: check if the Docker image exists\n+ `check workdir`: confirm working dir is correct\n+ `check-deps`: check dependencies inside Docker\n+ `build`: Build the Docker image\n+ `serve`: Serve the website\n+ `server-container`: Build server container\n+ `pause`: Pause 1 second (to pause between commands)\n+ `address`: Get Docker container address/port\n+ `stop-server`: Stop the running web server\n+ `restart-server`: Restart the running web server\n+ `print-config`: print info on variables used\n+ `lint`: Run linters\n+ `test`: Run full testing suite\n+ `pytest`: Run pytest in Docker container\n+ `isort`: Run isort in Docker container\n+ `black`: Run black in Docker container\n+ `flake8`: Run flake8 in Docker container\n+ `mypy`: Run mypy in Docker container\n+ `install-act`: install act command\n+ `check-act`: check if act is installed\n+ `run-act-tests`: run GitHub action tests locally\n+ `shell`: Create interactive shell in Docker container\n\n#### Example Uses\nHere we will show some **common use cases** for the `Makefile`:\n\n+ **serve the website locally**: running the `make serve` will serve the website and\n  print out the *host*/*address* to your terminal.\n\n+ **test the website locally**: running the `make pytest` will run **ONLY** the *Python*\n  tests (written with *pytest*) on the current website.\n\n+ **build docker image**: running `make build` will build the\n  `ghcr.io/diogenesanalytics/parley:master` *Docker image* locally.\n\n+ **stop the web server**: running `make stop-server` will stop any currently *running*\n  server deployed by `make serve`.\n\n+ **get local server address**: running `make address` will get the *host*/*port* for\n  the server deployed previously by `make serve` (if any exist).\n\n+ **run specific tests**: running `make shell` will allow start up a **bash** instance\n  inside the `ghcr.io/diogenesanalytics/parley:master` *Docker image*, from which you\n  can then run a *specific subset* of tests (**e.g.** `pytest -m website`).\n\n## References\n[^1]: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#input_types\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiogenesanalytics%2Fparley","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdiogenesanalytics%2Fparley","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdiogenesanalytics%2Fparley/lists"}