You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airavata.apache.org by ma...@apache.org on 2020/05/22 21:58:24 UTC

[airavata-django-portal] branch AIRAVATA-3324-custom-input-editor-autocomplete-input-editor updated: AIRAVATA-3324 Adding documentation

This is an automated email from the ASF dual-hosted git repository.

machristie pushed a commit to branch AIRAVATA-3324-custom-input-editor-autocomplete-input-editor
in repository https://gitbox.apache.org/repos/asf/airavata-django-portal.git


The following commit(s) were added to refs/heads/AIRAVATA-3324-custom-input-editor-autocomplete-input-editor by this push:
     new a9b69c3  AIRAVATA-3324 Adding documentation
a9b69c3 is described below

commit a9b69c38cc69b003a9e3fa35266ed7c7c7c823da
Author: Marcus Christie <ma...@apache.org>
AuthorDate: Fri May 22 17:17:35 2020 -0400

    AIRAVATA-3324 Adding documentation
---
 docs/admin/app_inputs.md           | 268 +++++++++++++++++++++++++++++++++++++
 docs/images/app-input-metadata.png | Bin 0 -> 244374 bytes
 mkdocs.yml                         |   1 +
 3 files changed, 269 insertions(+)

diff --git a/docs/admin/app_inputs.md b/docs/admin/app_inputs.md
new file mode 100644
index 0000000..4d1b4b1
--- /dev/null
+++ b/docs/admin/app_inputs.md
@@ -0,0 +1,268 @@
+# Advanced Applicaton Input Configuration
+
+The Airavata Django Portal supports customization of the user interface used to
+configure an application input. For example, instead of the default text input
+box for a string input, with customization the UI can be configured to be a drop
+down list of options.
+
+To configure application inputs one needs to provide JSON configuration in the
+**Advanced Input Field Modification Metadata** field of the application input.
+To get there:
+
+1. Select **Settings** from the drop down menu in the header.
+2. You should see the **Application Catalog**. If not, click the gears icon on
+   the left hand side.
+3. Select the application you want to configure by clicking on it.
+4. Select the _Interface_ tab.
+5. Scroll down to the _Input Field_ that you want to customize then scroll down
+   to the **Advanced Input Field Modification Metadata** text box. This is the
+   field where you will input your JSON configuration. This field will outline
+   in green when the JSON is valid and in red when invalid. See the following
+   screenshot.
+
+![Screenshot of Application Interface editor, highlighting the input JSON metadata field](../images/app-input-metadata.png)
+
+## Validation
+
+### Example
+
+```json
+{
+    "editor": {
+        "ui-component-id": "textarea-input-editor",
+        "config": {
+            "rows": 6
+        },
+        "validations": [
+            {
+                "type": "min-length",
+                "value": 10
+            },
+            {
+                "type": "max-length",
+                "value": 200
+            },
+            {
+                "type": "regex",
+                "value": "^[XYL\\s]+$",
+                "message": "Target sequence may only contain letters X, Y and L."
+            }
+        ]
+    }
+}
+```
+
+## Dependencies
+
+You can hide/show inputs based on the values of other inputs. For example, if
+the option selected in input A is 'list-of-urls' then you can have input B show
+a field to upload a file.
+
+### Example
+
+```json
+{
+    "editor": {
+        "dependencies": {
+            "show": {
+                "Select reading options": {
+                    "comparison": "equals",
+                    "value": "list-urls"
+                }
+            }
+        }
+    }
+}
+```
+
+## Alternate UI Components
+
+### Checkboxes
+
+#### Example
+
+```json
+{
+    "editor": {
+        "ui-component-id": "checkbox-input-editor",
+        "config": {
+            "options": [
+                {
+                    "value": "a",
+                    "text": "A label"
+                },
+                {
+                    "value": "b",
+                    "text": "B label"
+                },
+                {
+                    "value": "c",
+                    "text": "C label"
+                }
+            ]
+        }
+    }
+}
+```
+
+### Radio Buttons
+
+#### Example
+
+```json
+{
+    "editor": {
+        "ui-component-id": "radio-button-input-editor",
+        "config": {
+            "options": [
+                {
+                    "value": "breakfast",
+                    "text": "Breakfast"
+                },
+                {
+                    "value": "lunch",
+                    "text": "Lunch"
+                },
+                {
+                    "value": "dinner",
+                    "text": "Dinner"
+                }
+            ]
+        }
+    }
+}
+```
+
+### Selects
+
+#### Example
+
+```json
+{
+    "editor": {
+        "ui-component-id": "select-input-editor",
+        "config": {
+            "options": [
+                {
+                    "value": "breakfast",
+                    "text": "Breakfast"
+                },
+                {
+                    "value": "lunch",
+                    "text": "Lunch"
+                },
+                {
+                    "value": "dinner",
+                    "text": "Dinner"
+                }
+            ]
+        }
+    }
+}
+```
+
+### Autocomplete
+
+The Autocomplete UI component looks up matching entries for the given substring
+typed by the user. This one requires that a custom Django app be developed to
+implement the REST API for returning autocomplete suggestions.
+
+#### REST API contract
+
+-   URL is called with query parameter search with value of whatever the user
+    has currently typed
+-   URL should return a JSON response with a search key and the value of that
+    key used for the search and an results key with a list matching results,
+    limited to the top 10. Each result should have a text key with the text
+    displayed to the user and a value key which is the value applied to the
+    experiment input if selected. For example:
+
+```json
+{
+    "search": "mammal",
+    "results": [
+        {
+            "text": "Horse",
+            "value": "horse"
+        },
+        {
+            "text": "Mouse",
+            "value": "mouse"
+        }
+    ]
+}
+```
+
+-   URL can also be called with query parameter exact with a value that was
+    previously returned. This call is made by the UI to retrieve the "text"
+    value to display to the user for this value. The JSON response should be
+    similar to the above except that it should only have one result:
+
+```json
+{
+    "search": "horse",
+    "results": [
+        {
+            "text": "Horse",
+            "value": "horse"
+        }
+    ]
+}
+```
+
+-   If the exact query parameter is specified and there is no match for that
+    value, the JSON response should have HTTP status 404. The error reason can
+    be added to the "detail" key of the response body, for example:
+
+```json
+{
+    "detail": "No matching value was found."
+}
+```
+
+#### Example REST API implementation
+
+To create the REST API backend needed by the Autocomplete component, first you need a create a custom Django app. See [Custom Django Apps](../dev/custom_django_app) for more information.
+
+Here's a simple implementation of a view function that looks up words in the system dictionary file:
+
+```python
+def test_autocomplete_search(request):
+    """Find matching words for given search string."""
+    import re
+    if 'search' in request.GET:
+        query = request.GET['search']
+        pattern = re.compile(re.escape(query), re.IGNORECASE)
+    elif 'exact' in request.GET:
+        query = request.GET['exact']
+        pattern = re.compile(r"^" + re.escape(query) + r"$")
+    else:
+        return generic_json_exception_response(
+            "Missing required query parameter: one of 'search' or 'exact'", status=400)
+
+    matches = []
+    with open("/usr/share/dict/words", 'r') as f:
+        matches = [line.strip() for line in f if pattern.search(line)]
+    # TODO: if 'exact', make sure len(matches) == 1. if 0, then return 404
+    if 'exact' in request.GET and len(matches) == 0:
+        return generic_json_exception_response(f"No match for exact = {request.GET['exact']}", status=404)
+    return JsonResponse({
+        "search": query,
+        "results": [{"text": m, "value": m} for m in matches[:20]]
+    })
+```
+
+See also a real world example [miga-autocomplete](https://github.com/bio-miga/miga-autocomplete).
+
+#### Example Input Metadata Configuration
+
+```json
+{
+    "editor": {
+        "ui-component-id": "autocomplete-input-editor",
+        "config": {
+            "url": "/custom/search/"
+        }
+    }
+}
+```
diff --git a/docs/images/app-input-metadata.png b/docs/images/app-input-metadata.png
new file mode 100644
index 0000000..b9a8f87
Binary files /dev/null and b/docs/images/app-input-metadata.png differ
diff --git a/mkdocs.yml b/mkdocs.yml
index 7740248..74cecb1 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -13,6 +13,7 @@ nav:
     - Developing the Backend: dev/developing_backend.md
     - Developing a Wagtail Export (theme): dev/wagtail_export.md
   - Administrator Guide:
+    - Application Input Customization: admin/app_inputs.md
     - Tusd Installation: admin/tusd.md
   - Tutorials:
     - Gateways 2019: tutorial/gateways2019_tutorial.md