Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(rjsf): add anchor widget with find-and-replace capabilities #59

Merged
merged 1 commit into from
Aug 9, 2024

Conversation

benforshey
Copy link
Contributor

This RJSF widget was made for the Test Configuration model (currently only in UAT mEditor). I'll include the entire model schema you'll need, below.

To manually test this, please

  1. use the model schema below
  2. copy the Test Configuration model to your locally-running mEditor instance
  3. create at least one Test Configuration entry

To run the unit tests

  1. cd packages/app
  2. `npm t

Test Configuration Model Schema (not just the RJSF schema and layout)

{
  "icon": {
    "name": "fa-code",
    "color": "#46f0f0"
  },
  "titleProperty": "VariableEntryID",
  "category": "Configuration",
  "workflow": "Edit",
  "name": "Test Configuration",
  "description": "Test Cases for GDDS and Cloud Giovanni",
  "schema": "{\n    \"$schema\": \"http://json-schema.org/schema#\",\n    \"type\": \"object\",\n    \"properties\": {\n        \"RunURL\": {\n          \"title\": \"Generated URL for running this test suite.\",\n          \"description\": \"If the UTF is running on your machine, this URL will trigger all Test Cases in this configuration\",\n          \"type\": \"string\"\n        },\n        \"VariableEntryID\": {\n            \"title\": \"Associated Variable Entry ID\",\n            \"description\": \"The Entry ID for a variable should be CollectionEntryID_VariableShortName.\",\n            \"type\": \"string\"\n        },\n        \"EntryID\": {\n            \"type\": \"object\",\n            \"properties\": {\n                \"CollectionEntryID\": {\n                    \"title\": \"Associated Collection Entry ID\",\n                    \"description\": \"The Entry ID of the collection that the variable is associated with.  The enum is made up of all possible GES DISC collections in the mEditor database, similar to Related Datasets in other UUI content types.\",\n                    \"type\": \"string\",\n                    \"enum\": [\"placeholder\"]\n                },\n                \"ShortName\": {\n                    \"title\": \"Variable Short Name\",\n                    \"description\": \"The variable short name, which corresponds to CMR's Name field.\",\n                    \"type\": \"string\",\n                    \"minLength\": 1,\n                    \"maxLength\": 256\n                }\n            },\n            \"required\": [\"CollectionEntryID\", \"ShortName\"]\n        },\n        \"TestCases\": {\n            \"type\": \"array\",\n            \"title\": \"Test Cases\",\n            \"description\": \"List of test cases associated with an VariableEntryID\",\n            \"items\": {\n                \"type\": \"object\",\n                \"properties\": {\n                    \"Provider\": {\n                        \"description\": \"Collection provider.\",\n                        \"type\": \"string\",\n                        \"default\": \"GES_DISC\",\n                        \"minLength\": 1,\n                        \"maxLength\": 256\n                    },\n                    \"Bounding_Box\": {\n                        \"description\": \"Bounding box subsetting format\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"Southernmost_Latitude\": {\n                                \"type\": \"number\",\n                                \"minimum\": -90,\n                                \"maximum\": 90\n                            },\n                            \"Westernmost_Longitude\": {\n                                \"type\": \"number\",\n                                \"minimum\": -180,\n                                \"maximum\": 180\n                            },\n                            \"Northernmost_Latitude\": {\n                                \"type\": \"number\",\n                                \"minimum\": -90,\n                                \"maximum\": 90\n                            },\n                            \"Easternmost_Longitude\": {\n                                \"type\": \"number\",\n                                \"minimum\": -180,\n                                \"maximum\": 180\n                            }\n                        }\n                    },\n                    \"Time_Bounds\": {\n                        \"description\": \"Temporal range in ISO8601 format\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"Start_Time\": {\n                                \"description\": \"Temporal range start in ISO8601 format.\",\n                                \"type\": \"string\",\n                                \"format\": \"date-time\"\n                            },\n                            \"End_Time\": {\n                                \"description\": \"Temporal range end in ISO8601 format.\",\n                                \"type\": \"string\",\n                                \"format\": \"date-time\"\n                            }\n                        }\n                    },\n                    \"Services\": {\n                        \"description\": \"Service to be tested and compared\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"ServiceA\": {\n                                \"description\": \"Service to be tested and compared with service B.\",\n                                \"type\": \"string\",\n                                \"enum\": [\"goss\", \"hoss\", \"gl2ss\", \"hl2ss\"]\n                            },\n                            \"ServiceB\": {\n                                \"description\": \"Service to be tested and compared with service A.\",\n                                \"type\": \"string\",\n                                \"enum\": [\"goss\", \"hoss\", \"gl2ss\", \"hl2ss\"]\n                            }\n                        }\n                    },\n                    \"Environments\": {\n                        \"description\": \"Service environment\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                            \"EnvironmentA\": {\n                                \"description\": \"Service environment.\",\n                                \"type\": \"string\",\n                                \"enum\": [\"prod\", \"uat\"]\n                            },\n                            \"EnvironmentB\": {\n                                \"description\": \"Service environment.\",\n                                \"type\": \"string\",\n                                \"enum\": [\"prod\", \"uat\"]\n                            }\n                        }\n                    }\n                },\n                \"required\": [\"Bounding_Box\", \"Provider\", \"Services\", \"Environments\"]\n            }\n        }\n    },\n    \"required\": [\"VariableEntryID\", \"EntryID\", \"TestCases\"]\n}",
  "layout": "{\n    \"ui:order\": [\"RunURL\", \"VariableEntryID\", \"*\"],\n    \"RunURL\": {\n        \"ui:widget\": \"anchor\",\n        \"ui:options\": {\n            \"href\": \"http://localhost:8080/service-request-from-config?variable_entry_id=******\",\n            \"text\": \"\",\n            \"change\": {\n                \"every\": \"***\",\n                \"to\": [\"FIELD_LOOKUP:EntryID\", \"FIELD_LOOKUP:VariableEntryID\"]\n              }\n        }\n    },\n    \"VariableEntryID\": {\n        \"ui:widget\": \"concatenated\",\n        \"ui:options\": {\n            \"fields\": [\"EntryID_CollectionEntryID\", \"EntryID_ShortName\"],\n            \"delimeter\": \"_\"\n        }\n    },\n    \"EntryID\": {\n        \"CollectionEntryID\": {\n            \"ui:widget\": \"multi-select\"\n        }\n    }\n}",
  "templates": [
    {
      "jsonpath": "$.properties.EntryID.properties.CollectionEntryID.enum",
      "macro": "list Collection%20Metadata.Combined_EntryID"
    }
  ]
}


useEffect(() => {
// @ts-expect-error
if (!!options.change.every) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the instance of this widget (declared in your model's schema) has the change.every field, run a find and replace with macro support.


return (
<a href={href} target="_blank" rel="noopener noreferrer">
{options.text || href}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Allow the schema to declare the link's text, or fallback to the href.

@@ -1,9 +1,9 @@
import React, { useState, useEffect } from 'react'
import type { WidgetProps } from '@rjsf/utils'
import { getTemplate } from '@rjsf/utils'
import { ID_PREFIX } from './constants'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lifted up to use in another file.

// Starting from the source string, iterate through every entry in "to", replacing with either a macro's return value or a value.
return to.reduce((accumulator, current) => {
// We may have a MACRO_NAME:FieldName combo, or we may have a value.
const [macroNameOrValue, maybeFieldName] = current.split(':')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't write an ABFN grammar this time for our little macro DSL, but the idea is commended here. The tests show that you can pass in any combo: a value, a MACRO:value, or a MACRO, and this will still work.

"MyProperty": {
"ui:widget": "anchor",
"ui:options": {
"href": "http://localhost:8080/service-request-from-config?variable_entry_id=******",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a cool solution, though I'd be interested in your thought process for using this vs. a named template like Handlebars

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haha, honestly, more of a hindsight is 20/20 moment. I think Mustache / Handlebars would have worked great here! Even just using a named template would probably be an improvement. We could add that under another field (like every, but maybe named...but then maybe we'd need to make the change an array, since every => to wouldn't have the right relationship).

@benforshey benforshey merged commit f5ae6d4 into main Aug 9, 2024
5 checks passed
@benforshey benforshey deleted the feature/GDDS-859-create-test-config-button branch August 9, 2024 14:58
@benforshey benforshey restored the feature/GDDS-859-create-test-config-button branch September 19, 2024 20:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants