openshift / origin-web-catalog

Apache License 2.0
18 stars 60 forks source link

Add limited 'oneOf' json schema dependencies support for plan schemas. #677

Closed david-martin closed 4 years ago

david-martin commented 6 years ago

This change examines the json schema object in the service plan, looking for a dependencies object. If this exists, any oneOf property dependencies defined will be examined and a corresponding angular-schema-form condition will be added to the form definition so specified fields will only be shown when the corresponding option is selected/entered in another field.

Short clip of how it looks https://youtu.be/MX-G0TjaP7E

Example plan

{
  "metadata": {
    "name": "5f04a3f508d7615a422863814f58ad98"
  },
  "spec": {
    "clusterServiceBrokerName": "ansible-service-broker", // some fields omitted
    "externalMetadata": {
      "schemas": {
        "service_binding": {},
        "service_instance": {
          "create": {
            "openshift_form_definition": [
              "eg_enum_param",
              "eg_conditional_one",
              "eg_conditional_two",
              "eg_boolean_param",
              "eg_conditional_boolean_one",
              "eg_conditional_boolean_two"
            ]
          },
          "update": {}
        }
      }
    },
    "instanceCreateParameterSchema": {
      "$schema": "http://json-schema.org/draft-04/schema",
      "additionalProperties": false,
      "dependencies": {
        "eg_boolean_param": {
          "properties": {
            "eg_conditional_boolean_one": {
              "title": "Example Shown When True",
              "type": "string"
            },
            "eg_conditional_boolean_two": {
              "title": "Example Also Shown When True",
              "type": "string"
            }
          },
          "required": [
            "eg_conditional_boolean_one",
            "eg_conditional_boolean_two"
          ]
        },
        "eg_enum_param": {
          "oneOf": [
            {
              "properties": {
                "eg_conditional_one": {
                  "title": "Example Shown If 'Yes' or 'Maybe'",
                  "type": "string"
                },
                "eg_enum_param": {
                  "enum": [
                    "Yes",
                    "Maybe"
                  ]
                }
              },
              "required": [
                "eg_conditional_one"
              ]
            },
            {
              "properties": {
                "eg_conditional_two": {
                  "title": "Example Shown if 'No'",
                  "type": "string"
                },
                "eg_enum_param": {
                  "enum": [
                    "No"
                  ]
                }
              },
              "required": [
                "eg_conditional_two"
              ]
            }
          ]
        }
      },
      "properties": {
        "eg_boolean_param": {
          "title": "Conditional Example Boolean",
          "type": "boolean"
        },
        "eg_enum_param": {
          "default": "Yes",
          "enum": [
            "Yes",
            "No",
            "Maybe"
          ],
          "title": "Conditional Example",
          "type": "string"
        }
      },
      "type": "object"
    } // some fields omitted
  }
}

Example parameters in an apb.yml (pending related broker changes in https://github.com/openshift/ansible-service-broker/pull/928)

plans:
  - name: default
    description: __DEPENDENCIES
    free: True
    metadata: {}
    parameters:
    - name: eg_enum_param
      type: enum
      title: Conditional Example
      default: "Yes"
      enum: ["Yes", "No", "Maybe"]
    - name: eg_conditional_one
      title: Example Shown If 'Yes' or 'Maybe'
      type: string
      dependencies:
      - key: eg_enum_param
        value: ["Yes", "Maybe"]
    - name: eg_conditional_two
      title: Example Shown if 'No'
      type: string
      dependencies:
      - key: eg_enum_param
        value: "No"
    - name: eg_boolean_param
      title: Conditional Example Boolean
      type: boolean
    - name: eg_conditional_boolean_one
      title: Example Shown When True
      type: string
      dependencies:
      - key: eg_boolean_param
    - name: eg_conditional_boolean_two
      title: Example Also Shown When True
      type: string
      dependencies:
      - key: eg_boolean_param

Changes based on initial integration with broker (with @philipgough)

david-martin commented 6 years ago

ping @spadgett @PhilipGough @pb82 @maleck13

Related to UI & Broker changes discussed in https://github.com/openshift/ansible-service-broker/issues/859 & https://github.com/openshift/origin-web-catalog/pull/675

maleck13 commented 6 years ago

In the example I see a field always shows. Is it possible to not show any fields also? excuse my ignorance just not sure

david-martin commented 6 years ago

@maleck13 do you mean "don't show this field if another field has a specific value" ?

If yes, I don't think that's part of json schema dependencies. i.e. you define fields that are dependencies of others, but not fields that are negated dependencies. You can workaround this though quite easily e.g

In this case, field 3 & 4 won't be shown if option 1 is selected on field 1.

Is there a use case you're thinking of?

david-martin commented 6 years ago

@philipgough I've added support for below if you want to try it again:

david-martin commented 6 years ago

After discussion on https://github.com/openshift/ansible-service-broker/issues/859#issuecomment-387359151 I'll look to round out this PR by allowing oneOf conditions with booleans and numbers (not just string).

david-martin commented 6 years ago

@spadgett This is ready for review now. Where would be an appropriate place for documenting this catalog feature?

david-martin commented 6 years ago

@spadgett Thanks for the feedback. My typescript skills are obviously lacking :)

I've pushed up changes for re-review

maleck13 commented 6 years ago

@spadgett ok to merge this now as it is generically useful

openshift-bot commented 4 years ago

Issues go stale after 90d of inactivity.

Mark the issue as fresh by commenting /remove-lifecycle stale. Stale issues rot after an additional 30d of inactivity and eventually close. Exclude this issue from closing by commenting /lifecycle frozen.

If this issue is safe to close now please do so with /close.

/lifecycle stale

david-martin commented 4 years ago

Out of date, no longer required