Descriptor Picker
Overview
The descriptor picker allows the platform team to use a descriptor as a source of options for a field.
Configuration
As an example, consider the following descriptor:
# your component/system/ontology/whatever descriptor
spec:
# other irrelevant properties
mesh:
specific:
profiles:
- name: Premium
description: A premium profile
- name: Lite
description: A lite profile
Leveraging the Descriptor Picker, you can present to users a dropdown field with the options that are present under any descriptor's field, in our case the chosen field is spec.mesh.specific.profiles
, that is a list of items:
As you noticed, under spec.mesh.specific.profiles
we found a list of values, but you would obtain the same result even if there was a dictionary. Example:
# your component/system/ontology/whatever descriptor
spec:
# other irrelevant properties
mesh:
specific:
profiles:
premium:
name: Premium
description: A premium profile
lite:
name: Lite
description: A lite profile
Manipulating the DescriptorPicker output using Nunjucks
When the user selects any of the options presented through a DescriptorPicker, it is implicitly extracting the portion of the descriptor under the path that corresponds to the selected option in the descriptor. For instance, in the example above, the value of the profile
field in the form context will be a whole new descriptor with this shape:
name: Premium
description: A premium profile
If you have another DescriptorPicker that is reading up the value from the profile
field, you should take into account the transformations happening behind the scenes.
However, when you want to use the value of any of the DescriptorPicker fields, in the steps section of a template, keep in mind that the field value has the following structure:
type Option = {
/**
* The display name of the option
* if `optionDisplayNameAt` property is not used in the configuration for the DescriptorPicker:
* - if the options are parsed from an array of items, the default display name is the item index in the array
* - if the options are parsed from a dictionary of items, the default display name is the key of the item in the dictionary
*/
label: string;
/**
* Unique identifier of the option among the list of options
* for options coming from an array, this is the index
* for options coming from a dictionary, this is its key
*/
key: string;
/**
* The portion of the descriptor at the same level of the selected option
*/
value: Descriptor;
};
And here is an example AccessControlRequestTemplate where we want to prepare the data coming from the example above with profile
, membershipTypes
and regions
for an access request, before sending it to the Access Request Action:
# template.yaml
# other irrelevant properties
spec:
steps:
- id: access-request
name: Send Access Request
action: access-request:send
input:
fields:
profile: '${{ parameters.profile.value.name }}' # Premium
membershipType: '${{ parameters.membershipType.key }}' # shortTerm
region: '${{ parameters.region.value.name }}' # EU
selectedGroup: '${{ parameters.region.value.group }}' # group:premium_short_eu
The configuration for the DescriptorPicker to reproduce the example above is the following:
parameters:
- title: Access Request
properties:
profile:
type: object # don't change it
ui:field: DescriptorPicker
title: Profile
description: Select the profile associated to your user account
sourceType: descriptor
source: .
optionsAt: spec.mesh.specific.profiles
optionsDisplayNameAt: name
Apart from type
, ui:field
that are to be left as shown above and title
and description
that are self-explanatory, let's dive into the options for the descriptor picker:
property | description | possible values |
---|---|---|
sourceType | The type of the source that this picker consumes. | descriptor , field |
source | The location of the descriptor, if sourceType is descriptor then the only allowed value will be . , meaning that witboost will place a descriptor that is contextually meaningful to the template where this picker is being used. E.g. for the Access Control Request Template, the available descriptor in the context will be the resource's descriptor that is being requested. | . if sourceType is descriptor otherwise if sourceType is field then any field present under parameters.properties in the template fits here |
optionsAt | The path in the descriptor where a list, or dictionary, of options is available | <string> |
optionsDisplayNameAt | (optional) The item's field that can be used as a display name. e.g. if all items in the list have a name field, it can be used as a display name | <string> |
DescriptorPicker for complex structures
The DescriptorPicker also supports complex structures of nested options, either they are dictionaries, lists or a combination of them. Let's take a more complex descriptor as a reference:
spec:
mesh:
specific:
profiles:
- name: Premium
membershipTypes:
longTerm:
name: Long Term
regions:
- name: EU
group: group:premium_long_eu
- name: US
group: group:premium_long_us
shortTerm:
name: Short Term
regions:
- name: EU
group: group:premium_short_eu
- name: US
group: group:premium_short_us
- name: Lite
membershipTypes:
longTerm:
name: Long Term
regions:
- name: EU
group: group:lite_long_eu
- name: US
group: group:premium_long_us
shortTerm:
name: Short Term
regions:
- name: EU
group: group:lite_short_eu
- name: US
group: group:lite_short_us
In this example, the options are nested, meaning that choosing one of the profiles
influences the list of options for the membershipTypes
and as a consequence also for regions
. Notice also that profiles
is a list of items, membershipTypes
is a dictionary and regions
is a list of items.
The result of leveraging the DescriptorPicker is shown below:
Given by this configuration:
parameters:
- title: Access Request
properties:
profile:
type: object
ui:field: DescriptorPicker
title: Profile
sourceType: descriptor
source: .
optionsAt: spec.mesh.specific.profiles
optionsDisplayNameAt: name
membershipType:
type: object
ui:field: DescriptorPicker
title: Membership Type
sourceType: field
source: profile
optionsAt: membershipTypes
optionsDisplayNameAt: name
region:
type: object
ui:field: DescriptorPicker
title: Region
sourceType: field
source: membershipType
optionsAt: regions
optionsDisplayNameAt: name
As you can notice, region
uses the output coming from membershipType
, which in turn uses the output coming from profile
.