Workflows Form Inputs Library
There are various ways in which you can take input from users in IDP Workflows. All types of form input types and examples are listed in this document.
Simple text input
Simple input with basic validations
Example workflows.yaml
Example YAML
parameters:
- title: Fill in some steps
properties:
name:
title: Simple text input
type: string
description: Description about input
maxLength: 8
pattern: "^([a-zA-Z][a-zA-Z0-9]*)(-[a-zA-Z0-9]+)*$"
ui:autofocus: true
ui:help: "Hint: additional description..."
Multi-line text input
Example workflows.yaml
Example YAML
parameters:
- title: Fill in some steps
properties:
multiline:
title: Text area input
type: string
description: Insert your multi line string
ui:widget: textarea
ui:options:
rows: 10
ui:help: 'Hint: Make it strong!'
ui:placeholder: |
a=50
b=60
sh << word
> echo "Equation: a + b = 110"
> echo $(($a + $b))
> echo ""
> echo "Inside Here Tag, Assignment c=110"
> c=`expr $a + $b`
> echo $c
> word
Dynamically Fetch Values in Workflows
You can dynamically fetch values in the Workflows fields using UI Pickers, which are in-built. There are two kinds of UI Pickers:
Array options
Array with strings
Example workflows.yaml
Array with distinct values
Values mentioned under enum
needs to be distinct, duplicate values aren't allowed under enum
.
Example YAML
parameters:
- title: Fill in some steps
required:
- name
properties:
name:
title: Name
type: string
description: Unique name of the component
volume:
title: Volume Type
type: string
description: The volume type to be used
default: 'Cold HDD'
enum:
- 'Provisioned IOPS'
- 'Cold HDD'
- 'Throughput Optimized HDD'
- 'Magnetic'
Array with duplicate values
Example YAML
parameters:
- title: Fill in some steps
properties:
volume_type:
title: Volume Type
type: string
description: The volume type to be used
default: gp2
enum:
- gp2
- gp3
- io1
- io2
- sc1
- st1
- standard
enumNames:
- 'General Purpose SSD (gp2)'
- 'General Purpose SSD (gp3)'
- 'Provisioned IOPS (io1)'
- 'Provisioned IOPS (io2)'
- 'Cold HDD (sc1)'
- 'Throughput Optimized HDD (st1)'
- 'Magnetic (standard)'
A multiple choices list
Example workflows.yaml
Example YAML
parameters:
- title: Fill in some steps
properties:
name:
title: Select environments
type: array
items:
type: string
enum:
- production
- staging
- development
uniqueItems: true
ui:widget: checkboxes
Array with Custom Objects
Example workflows.yaml
Example YAML
parameters:
- title: Fill in some steps
properties:
arrayObjects:
title: Array with custom objects
type: array
minItems: 0
ui:options:
addable: true
orderable: true
removable: true
items:
type: object
properties:
array:
title: Array string with default value
type: string
default: value3
enum:
- value1
- value2
- value3
flag:
title: Boolean flag
type: boolean
ui:widget: radio
someInput:
title: Simple text input
type: string
Boolean options
Boolean
parameters:
- title: Fill in some steps
properties:
name:
title: Checkbox boolean
type: boolean
Boolean Yes or No options (Radio Button)
parameters:
- title: Fill in some steps
properties:
name:
title: Yes or No options
type: boolean
ui:widget: radio
Boolean multiple options
Example YAML
parameters:
- title: Fill in some steps
properties:
name:
title: Select features
type: array
items:
type: boolean
enum:
- "Enable scraping"
- "Enable HPA"
- "Enable cache"
uniqueItems: true
ui:widget: checkboxes
Conditional Inputs in Workflows
Conditionally set parameters
The if
keyword within the parameter uses nunjucks templating. The not
keyword is unavailable; instead, use JavaScript equality. e.g.: ${{ parameters.branchName if parameters.branchName else appendTimestamp("default-branch-name-") }}
Example YAML
spec:
parameters:
- title: Fill in some steps
properties:
path:
title: path
type: string
steps:
- id: fetch
name: Fetch template
action: fetch:template
input:
url: ${{ parameters.path if parameters.path else '/root' }}
Use parameters as conditional for fields
Example YAML
parameters:
- title: Fill in some steps
properties:
includeName:
title: Include Name?
type: boolean
default: true
dependencies:
includeName:
allOf:
- if:
properties:
includeName:
const: true
then:
properties:
lastName:
title: Last Name
type: string
One Of
: Helps you create a dropdown in the Workflow, where only one of all the options available could be selected.
Example workflows.yaml
Example YAML
dependencies:
technology:
oneOf:
- properties:
technology:
enum:
- java
java version:
type: "string"
enum:
- java8
- java11
All Of
: Helps you create a dropdown in the Workflow, where only all the options available could be selected.
Example workflows.yaml
Example YAML
type: object
allOf:
- properties:
lorem:
type:
- string
- boolean
default: true
- properties:
lorem:
type: boolean
ipsum:
type: string
Any Of
: Helps you to select from multiple properties where both can't be selected together at once.
Example workflows.yaml
The Example Workflow Explained
-
Parameters Structure The parameters section includes
age
as an integer anditems
as an array. Each item in the array can contain either afoo
orbar
property, utilizinganyOf
. -
Identification Methods The Workflow allows for two methods of identification using
anyOf
. Users can provide either:
- A first name and last name (defaulting
firstName
to "Chuck"), or - An ID code.
-
Required Fields The
age
field is required, while the fields under the two identification methods are optional but must comply with theanyOf
logic. -
Display Step The steps section includes a
debug:log
action to display the collected information based on the provided input.
Example YAML
type: object
properties:
age:
type: integer
title: Age
items:
type: array
items:
type: object
anyOf:
- properties:
foo:
type: string
- properties:
bar:
type: string
anyOf:
- title: First method of identification
properties:
firstName:
type: string
title: First name
default: Chuck
lastName:
type: string
title: Last name
- title: Second method of identification
properties:
idCode:
type: string
title: ID code
For more such references and validate your conditional steps take a look at the react-json schema project.
Upload a file using Workflows
There are 3 types of file upload.
- Single File
- Multiple Files
- Single File with Accept Attribute
Example YAML
#Example
title: Files
type: object
properties:
file:
type: string
format: data-url
title: Single file
files:
type: array
title: Multiple files
items:
type: string
format: data-url
filesAccept:
type: string
format: data-url
title: Single File with Accept attribute
Using Secrets
You may want to mark things as secret and make sure that these values are protected and not available through REST endpoints. You can do this by using the built-in ui:field: Secret
and ui:widget: password
.
ui:widget: password
needs to be mentioned under the first page
in-case you have multiple pages.
# example workflow.yaml
...
parameters:
- title: <PAGE-1 TITLE>
properties:
property-1:
title: title-1
type: string
property-2:
title: title-2
token:
title: Harness Token
type: string
ui:widget: password
ui:field: HarnessAuthToken
- title: <PAGE-2 TITLE>
properties:
property-1:
title: title-1
type: string
property-2:
title: title-2
- title: <PAGE-n TITLE>
...
You can define this property as any normal parameter, however the consumption of this parameter will not be available through ${{ parameters.myKey }}
you will instead need to use ${{ secrets.myKey }}
in your workflow.yaml
.
Parameters will be automatically masked in the review step.
Example YAML
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: v1beta3-demo
title: Test Action Workflow
description: Workflows Demo
spec:
owner: backstage/techdocs-core
type: service
parameters:
- title: Authentication
description: Provide authentication for the resource
required:
- username
- password
properties:
username:
type: string
# use the built in Secret field extension
ui:field: Secret
password:
type: string
ui:field: Secret
steps:
- id: setupAuthentication
action: auth:create
input:
# make sure to use ${{ secrets.parameterName }} to reference these values
username: ${{ secrets.username }}
password: ${{ secrets.password }}
Built in Filters
Workflow filters are functions that help you transform data, extract specific information, and perform various operations in Workflows.
This section introduces the built-in filters provided by Backstage and offers examples of how to use them in the Workflows. It's important to mention that Backstage also leverages the native filters from the Nunjucks library. For a complete list of these native filters and their usage, refer to the Nunjucks documentation.
parseRepoUrl
The parseRepoUrl
filter parse a repository URL into
its components, such as owner
, repository name
, and more.
Usage Example:
- id: log
name: Parse Repo URL
action: debug:log
input:
extra: ${{ parameters.repoUrl | parseRepoUrl }}
- Input:
github.com?repo=backstage&org=backstage
- Output: RepoSpec
parseEntityRef
The parseEntityRef
filter allows you to extract different parts of
an entity reference, such as the kind
, namespace
, and name
.
Usage example
- Without context
- id: log
name: Parse Entity Reference
action: debug:log
input:
extra: ${{ parameters.owner | parseEntityRef }}
- Input:
group:techdocs
- Output: CompoundEntityRef
- With context
- id: log
name: Parse Entity Reference
action: debug:log
input:
extra: ${{ parameters.owner | parseEntityRef({ defaultKind:"group", defaultNamespace:"another-namespace" }) }}
- Input:
techdocs
- Output: CompoundEntityRef
pick
This pick
filter allows you to select specific properties from an object.
Usage Example
- id: log
name: Pick
action: debug:log
input:
extra: ${{ parameters.owner | parseEntityRef | pick('name') }}
- Input:
{ kind: 'Group', namespace: 'default', name: 'techdocs' }
- Output:
techdocs
projectSlug
The projectSlug
filter generates a project slug from a repository URL
Usage Example
- id: log
name: Project Slug
action: debug:log
input:
extra: ${{ parameters.repoUrl | projectSlug }}
- Input:
github.com?repo=backstage&org=backstage
- Output:
backstage/backstage
Workflow UI Pickers
Collecting input from the user is a very large part of the Workflows as a whole. Sometimes the built-in components and fields just aren't good enough, and sometimes you want to enrich the form that the users sees with better inputs that fit better.
This is where Workflow UI Pickers come in.
Harness Specific UI Pickers
1. EntityFieldPicker
Only string data type
is supported for the EntityPicker
.
The input props that can be specified under ui:options
for the EntityFieldPicker
field extension.
displayField
This is used to fetch the value from catalog dynamically, corresponding to the key mentioned.
jiraprojectID:
title: Jira Project Key
type: string
description: The key for your JIRA project
ui:field: EntityFieldPicker
ui:displayField: metadata.jiraProjectId
ui:options:
catalogFilter:
kind:
- Component
- Service
In the above example it will fetch all the jiraProjectId
for the software components kind
mentioned under catalogFilter
.
allowArbitraryValues
Whether to allow arbitrary user input. Defaults to true.
allowArbitraryValues
provides input validation when selecting an entity as the values you enter will correspond to a valid entity.
- Adding a valid entity with
allowArbitraryValues
asfalse
entity:
title: Entity
type: string
description: Entity of the component
ui:field: EntityFieldPicker
ui:options:
allowArbitraryValues: false
- Adding an arbitrary entity with
allowArbitraryValues
astrue
(default value)
entity:
title: Entity
type: string
description: Entity of the component
ui:field: EntityFieldPicker
ui:options:
allowArbitraryValues: true
catalogFilter
catalogFilter
supports filtering options by any field(s) of an entity.
- Get all entities of kind
Group
entity:
title: Entity
type: string
description: Entity of the component
ui:field: EntityFieldPicker
ui:options:
catalogFilter:
- kind: Group
- Get entities of kind
Group
and spec.typeteam
entity:
title: Entity
type: string
description: Entity of the component
ui:field: EntityFieldPicker
ui:options:
catalogFilter:
- kind: Group
spec.type: team
defaultKind
The default entity kind.
system:
title: System
type: string
description: System of the component
ui:field: EntityFieldPicker
ui:options:
catalogFilter:
kind: System
defaultKind: System
defaultNamespace
The ID of a namespace that the entity belongs to. The default value is default
.
- Listing all entities in the
default
namespace (default value)
entity:
title: Entity
type: string
description: Entity of the component
ui:field: EntityFieldPicker
ui:options:
defaultNamespace: default
2. HarnessOrgPicker
Fetches all the org ID dynamically.
#Example
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: your-workflow
...
spec:
...
parameters:
- title: Details
properties:
projectId:
title: Project Identifier
description: Harness Project Identifier
type: string
ui:field: HarnessProjectPicker
orgId:
title: Org Identifier
type: string
ui:field: HarnessOrgPicker
...
3. HarnessProjectPicker
Fetches all the project ID dynamically.
# Example workflow.yaml file
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: your-workflow
...
spec:
...
parameters:
- title: Details
properties:
projectId:
title: Project Identifier
description: Harness Project Identifier
type: string
ui:field: HarnessProjectPicker
4. HarnessAutoOrgPicker
It autopopulates org ID on project selection. So now when you select a project ID as an input the org ID gets selected automatically if required as an input.
- For
HarnessAutoOrgPicker
to work, it is suggested to name the Project Identifier under Properties asprojectId
and using theHarnessProjectPicker
.
# Example workflow.yaml file
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: your-workflow
...
spec:
...
parameters:
- title: Details
properties:
projectId:
title: Project Identifier
description: Harness Project Identifier
type: string
ui:field: HarnessProjectPicker
orgId:
title: Org Identifier
description: Harness org Identifier
type: string
ui:field: HarnessAutoOrgPicker
- In case the properties Project Identifier is named something else other than
projectId
in that case for the custom action to function as desired we need to add it as a dependency underprojectPickerRef
# Example workflow.yaml file
properties:
<ANY NAME OTHER THAN projectId>:
title: Project Identifier
description: Harness Project Identifier
type: string
ui:field: HarnessProjectPicker
orgId:
title: Org Identifier
description: Harness org Identifier
type: string
ui:field: HarnessAutoOrgPicker
dependencies:
projectPickerRef:
- 'project_name'
Other UI Pickers
1. OwnerPicker
OwnerPicker
is used for developers to pick a User Group from the list of Groups that exist in the account.
allowArbitraryValues
Whether to allow arbitrary user input. Defaults to true.
allowArbitraryValues
provides input validation when selecting an owner as the values you enter will correspond to a valid owner.
- Adding a valid owner with
allowArbitraryValues
asfalse
owner:
title: Owner
type: string
description: Owner of the component
ui:field: OwnerPicker
ui:options:
allowArbitraryValues: false
- Adding an arbitrary owner with
allowArbitraryValues
astrue
(default value)
owner:
title: Owner
type: string
description: Owner of the component
ui:field: OwnerPicker
ui:options:
allowArbitraryValues: true
catalogFilter
catalogFilter
supports filtering options by any field(s) of an entity.
- Get all entities of kind
Group
owner:
title: Owner
type: string
description: Owner of the component
ui:field: OwnerPicker
ui:options:
catalogFilter:
- kind: Group
- Get entities of kind
Group
and spec.typeteam
owner:
title: Owner
type: string
description: Owner of the component
ui:field: OwnerPicker
ui:options:
catalogFilter:
- kind: Group
spec.type: team
defaultNamespace
The ID of a namespace that the owner belongs to. The default value is default
.
- Listing owners in the
default
namespace (default value)
owner:
title: Owner
type: string
description: Owner of the component
ui:field: OwnerPicker
ui:options:
catalogFilter:
- kind: Group
defaultNamespace: default
- Listing owners in the
payment
namespace
owner:
title: Owner
type: string
description: Owner of the component
ui:field: OwnerPicker
ui:options:
catalogFilter:
- kind: Group
defaultNamespace: payment
2. EntityPicker
Only string data type
is supported for the EntityPicker
.
The input props that can be specified under ui:options
for the EntityPicker
field extension.
allowArbitraryValues
Whether to allow arbitrary user input. Defaults to true.
allowArbitraryValues
provides input validation when selecting an entity as the values you enter will correspond to a valid entity.
- Adding a valid entity with
allowArbitraryValues
asfalse
entity:
title: Entity
type: string
description: Entity of the component
ui:field: EntityPicker
ui:options:
allowArbitraryValues: false
- Adding an arbitrary entity with
allowArbitraryValues
astrue
(default value)
entity:
title: Entity
type: string
description: Entity of the component
ui:field: EntityPicker
ui:options:
allowArbitraryValues: true
catalogFilter
catalogFilter
supports filtering options by any field(s) of an entity.
- Get all entities of kind
Group
entity:
title: Entity
type: string
description: Entity of the component
ui:field: EntityPicker
ui:options:
catalogFilter:
- kind: Group
- Get entities of kind
Group
and spec.typeteam
entity:
title: Entity
type: string
description: Entity of the component
ui:field: EntityPicker
ui:options:
catalogFilter:
- kind: Group
spec.type: team
defaultKind
The default entity kind.
system:
title: System
type: string
description: System of the component
ui:field: EntityPicker
ui:options:
catalogFilter:
kind: System
defaultKind: System
defaultNamespace
The ID of a namespace that the entity belongs to. The default value is default
.
- Listing all entities in the
default
namespace (default value)
entity:
title: Entity
type: string
description: Entity of the component
ui:field: EntityPicker
ui:options:
defaultNamespace: default
3. MultiEntityPicker
The input props that can be specified under ui:options
for the MultiEntityPicker
field extension.
allowArbitraryValues
Whether to allow arbitrary user input. Defaults to true.
allowArbitraryValues
provides input validation when selecting an entity as the values you enter will correspond to a valid entity.
- Adding a valid entity with
allowArbitraryValues
asfalse
entity:
title: Entities
type: array
description: Entities of the component
ui:field: MultiEntityPicker
ui:options:
allowArbitraryValues: false
- Adding an arbitrary entity with
allowArbitraryValues
astrue
(default value)
entity:
title: Entities
type: array
description: Entities of the component
ui:field: MultiEntityPicker
ui:options:
allowArbitraryValues: true
catalogFilter
catalogFilter
supports filtering options by any field(s) of an entity.
- Get all entities of kind
Group
entity:
title: Entities
type: array
description: Entities of the component
ui:field: MultiEntityPicker
ui:options:
catalogFilter:
- kind: Group
- Get entities of kind
Group
and spec.typeteam
entity:
title: Entities
type: array
description: Entities of the component
ui:field: MultiEntityPicker
ui:options:
catalogFilter:
- kind: Group
spec.type: team
defaultKind
The default entity kind.
system:
title: System
type: array
description: Systems of the component
ui:field: MultiEntityPicker
ui:options:
catalogFilter:
kind: System
defaultKind: System
defaultNamespace
The ID of a namespace that the entity belongs to. The default value is default
.
- Listing all entities in the
default
namespace (default value)
entity:
title: Entity
type: array
description: Entities of the component
ui:field: MultiEntityPicker
ui:options:
defaultNamespace: default
- Listing all entities in the
payment
namespace
entity:
title: Entity
type: array
description: Entities of the component
ui:field: MultiEntityPicker
ui:options:
defaultNamespace: payment
The Repository Picker
In order to make working with repository providers easier, we've built a custom
picker that can be used by overriding the ui:field
option in the uiSchema
for a string
field. Instead of displaying a text input block it will render
our custom component that we've built which makes it easy to select a repository
provider, and insert a project or owner, and repository name.
You can see it in the above full example which is a separate step and it looks a little like this:
- title: Choose a location
required:
- repoUrl
properties:
repoUrl:
title: Repository Location
type: string
ui:field: RepoUrlPicker
ui:options:
allowedHosts:
- github.com
The allowedHosts
part should be set to where you wish to enable this Workflow
to publish to. And it can be any host that is listed in your integrations
config in app-config.yaml
.
Besides specifying allowedHosts
you can also restrict the Workflow to publish to
repositories owned by specific users/groups/namespaces by setting the allowedOwners
option. With the allowedRepos
option you are able to narrow it down further to a
specific set of repository names. A full example could look like this:
- title: Choose a location
required:
- repoUrl
properties:
repoUrl:
title: Repository Location
type: string
ui:field: RepoUrlPicker
ui:options:
allowedHosts:
- github.com
allowedOwners:
- backstage
- someGithubUser
allowedRepos:
- backstage
For a list of all possible ui:options
input props for RepoUrlPicker
, please visit here.
Using the Users oauth
token
There's a little extra magic that you get out of the box when using the
RepoUrlPicker
as a field input. You can provide some additional options under
ui:options
to allow the RepoUrlPicker
to grab a oauth
token for the user
for the required repository
.
This is great for when you are wanting to create a new repository, or wanting to perform operations on top of an existing repository.
A sample Workflow that takes advantage of this is like so:
Example YAML
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: v1beta3-demo
title: Test Action Workflow
description: Workflows Demo
spec:
owner: backstage/techdocs-core
type: service
parameters:
...
- title: Choose a location
required:
- repoUrl
properties:
repoUrl:
title: Repository Location
type: string
ui:field: RepoUrlPicker
ui:options:
# Here's the option you can pass to the RepoUrlPicker
requestUserCredentials:
secretsKey: USER_OAUTH_TOKEN
additionalScopes:
github:
- workflow
allowedHosts:
- github.com
...
steps:
...
- id: publish
name: Publish
action: publish:github
input:
allowedHosts: ['github.com']
description: This is ${{ parameters.name }}
repoUrl: ${{ parameters.repoUrl }}
# here's where the secret can be used
token: ${{ secrets.USER_OAUTH_TOKEN }}
...
You will see from above that there is an additional requestUserCredentials
object that is passed to the RepoUrlPicker
. This object defines what the
returned secret
should be stored as when accessing using
${{ secrets.secretName }}
, in this case it is USER_OAUTH_TOKEN
. And then you
will see that there is an additional input
field into the publish:github
action called token
, in which you can use the secret
like so:
token: ${{ secrets.USER_OAUTH_TOKEN }}
.
There's also the ability to pass additional scopes when requesting the oauth
token from the user, which you can do on a per-provider basis, in case your Workflow can be published to multiple providers.
Note, that you will need to configure a connector for your source code management (SCM) service to make this feature work.
Pre-fill workflows with URL Params
We can now automatically load IDP Workflow forms pre-filled using the formData
URL query parameter. e.g.: https://app.harness.io/ng/account/account_id/module/idp/create/templates/default/a-python-lambda?formData=%7B%22project_name%22%3A%22auto%20filled%22%7D
The query parameters ?formData=%7B%22project_name%22%3A%22auto%20filled%22%7
in the end of the URL allow you to automatically fill in values of the form. Please see the below table for explanation of individual tokens in the query param.
Item | Example Value | Explanation |
---|---|---|
formData | formData | Key of the query param.formData object is used to fill out IDP Workflow forms. |
{"key"%3A"value"} | {"title"%3A"Title from query params"} | Value of the query param. A JSON object with invalid URL characters encoded.: encodes to %3A |
Add Read only Fields
Using automatically filled out values is handy when wanting to direct users to use IDP Workflows with known good values. This also allows automation to be constructed around the Workflows, where the automation can provide fully constructed IDP URLs to the user. You can also prevent user from modifying the form values inserted from query params by making the form fields readonly
. See below example of a minimal form which would be filled using query params defined in the above explanation.
Example YAML
## Example Workflow
apiVersion: scaffolder.backstage.io/v1beta3
kind: Template
metadata:
name: test-workflow-pipeline
title: Test pipeline using Workflows
spec:
owner: name.owner
type: service
parameters:
- title: Repository Name
properties:
project_name:
title: Name your project
ui:readonly: true
type: string
token:
title: Harness Token
type: string
ui:widget: password
ui:field: HarnessAuthToken
steps:
- id: trigger
name: Creating your github repository
action: trigger:harness-custom-pipeline
input:
url: PIPELINE_URL
inputset:
github_org: ${{ parameters.project_name }}
apikey: ${{ parameters.token }}
output:
links:
- title: Pipeline Details
url: ${{ steps.trigger.output.PipelineUrl }}
For Use-Cases you don't find here
It is suggested to use the react-jsonschema-form playground to build the frontend(UI for Inputs) for use-cases that are not listed here. Nunjucks is templating engine for the Self Service Workflows.