Skip to main content

Custom Form Control

Requirements

Supported Environments

  • Private deployment
  • SAAS

ONES System Version

v6.90.0+

ONES CLI Version

v1.70.1+

npm install -g @ones/cli --registry=https://npm.partner.ones.cn/registry/
ones --version
1.70.1

Capability Overview

This document describes how to add a custom form control to the work item detail form, create form, and transition form via feature extensions.

Extension Configuration

Configuration

Add the following configuration to config/plugin.yaml.

oauth:
type:
- user
scope:
- read:project:issueField
extension:
- formControlExtension:
provider: smsprov2
slots:
- name: ones:form:control:content
entryUrl: modules/ones-form-control-content-nLtK/index.html
- name: ones:form:control:settings
entryUrl: modules/ones-form-control-settings-71OJ/index.html
config:
name: Custom control name
fieldUUIDs:
- 9ax9ExKt
- M3Fgzu3F
- EGx9jsaH
- LS5aqwaW
supportForms:
- detail
- create
- transition
controlTips: Control description

Note: The oauth-related configuration is mainly related to the Open API. Configure the plugin as needed. See the documentation: Open API

Slot Description

Plugin NameDescription
ones:form:control:contentThe slot where the custom form control renders its content in the form.
ones:form:control:settingsThe slot to implement custom settings in the form editor. If custom settings are not needed, omit this.

config Field Description

FieldTypeDescription
namestringCustom form control name
fieldUUIDsstring[]List of fields included in the custom form control
supportForms"detail" | "create" | "transition"Forms supported by the custom control. Currently only three (detail, create, transition). create requires detail.
controlTipsstringControl description shown in the form editor. Optional.

Example

Frontend Implementation

Custom Form Control Content Slot

  1. Create the entry file for rendering the slot content: web/src/modules/ones-form-control-content-nLtK/index.tsx.
import React from 'react'
import ReactDOM from 'react-dom'
import { ConfigProvider } from '@ones-design/core'
import { lifecycle, OPProvider } from '@ones-op/bridge'
import './index.css'
import { ControlContentExtension } from './control_content_extension'


ReactDOM.render(
<ConfigProvider>
<OPProvider>
<ControlContentExtension/>
</OPProvider>
</ConfigProvider>,
document.getElementById('ones-mf-root'),
)

lifecycle.onDestroy(() => {
ReactDOM.unmountComponentAtNode(document.getElementById('ones-mf-root') as HTMLElement)
})

  1. Implement the ControlContentExtension component.
import React, { useEffect } from 'react'
import type { FC } from 'react'
import { useExtensionContext, useExtensionConfig } from '@ones-op/sdk'

export const ControlContentExtension: FC = () => {
// Inside the plugin, call useExtensionContext to obtain the context passed by the product.
// Call useExtensionConfig to obtain the plugin configuration.
const extensionContext = useExtensionContext()
const extensionConfig = useExtensionConfig()

const {
fields,
fieldsConfig,
ctx,
values,
onSubmit,
onPermissionDenied,
type,
inEditor,
onChange,
settings,
} = extensionContext

return <div>your business logic</div>
}

  1. extensionContext Parameter Description
FieldTypeDescriptionDetail FormCreate FormTransition Form
namestringCustom form control name
inEditorbooleanWhether it is in the form editor
type"detail" | "create" | "transition"Current form type
fieldsIField[] Basic field information
fieldsConfigRecord<string, FieldConfig>Field configuration in the form, including: visible, required, placeholder, hasPermission
valuesRecord<string, any>Field values in the form
settingsRecord<string, any>Configuration of the custom control on the form
ctxControlContentExtensionContextContext information
onPermissionDenied(fieldUUID: string) => voidShows a toast for lack of permission by fieldUUID; handled by product
onSubmit(values: Record<string, { value: unknown; submitType?: SubmitTypeEnum }> ) => Promise<void>Callback to submit data
onChange(value: Record<string, any>) => void;Callback when data changes in create/transition forms

ControlContentExtensionContext Type

export interface ControlContentExtensionContext {
taskUUID?: string // Work item UUID; provided only in detail and transition forms
projectUUID?: string // Project UUID
issueTypeUUID?: string // Work item type UUID
taskDetailViewMode?: TaskDetailViewMode // Work item detail layout; only provided in detail form
taskStatus?: TaskStatus // Work item status; detail form only
transitionUUID?: string // Transition UUID; only available in transition form
formValues?: Record<string, any> // Form values; only in create and transition forms
}

export enum TaskDetailViewMode {
Wide = 'wide', // Wide detail layout
Narrow = 'narrow', // Narrow detail layout
}
export interface TaskStatus {
uuid: string
category: string
name: string
}
  1. Flow Description:

    Detail form: Call onSubmit with the data edited inside the custom control. After listening to onSubmit, the ONES will call the update API with the received parameters to update work item fields.

    Create and transition forms: Call onChange with the data edited inside the custom control. The ONES listens to onChange, saves the received values into the form, and submits all data together when the confirm button is clicked.

Custom Form Control Settings Slot

  1. Create the entry file for the custom settings slot: web/src/modules/ones-form-control-settings-71OJ/index.tsx.
import React from 'react'
import ReactDOM from 'react-dom'
import { ConfigProvider } from '@ones-design/core'
import { lifecycle, OPProvider } from '@ones-op/bridge'
import { ControlSettingsExtension } from './control_settings_extension'
import './index.css'

ReactDOM.render(
<ConfigProvider>
<OPProvider>
<ControlSettingsExtension />
</OPProvider>
</ConfigProvider>,
document.getElementById('ones-mf-root'),
)

lifecycle.onDestroy(() => {
ReactDOM.unmountComponentAtNode(document.getElementById('ones-mf-root') as HTMLElement)
})

  1. Implement the ControlSettingsExtension component.
import React, { useEffect } from 'react'
import type { FC } from 'react'
import { useExtensionContext, useExtensionConfig } from '@ones-op/sdk'

export const ControlSettingsExtension: FC = () => {
// Inside the plugin, call useExtensionContext to obtain the context passed by the ONES.
// Call useExtensionConfig to obtain the plugin configuration.
const extensionContext = useExtensionContext()
const extensionConfig = useExtensionConfig()
return <div>your business logic</div>
}
  1. extensionContext Parameter Description
NameTypeDescription
namestringPlugin name
type'detail' | 'create' | 'transition'Form type
fieldsIField[]Basic field information
valueRecord<string, any>Previously saved settings
ctxControlSettingsExtensionContextContext information
onChange(value: Record<string, any>) => Promise<void>Callback on settings change

ControlSettingsExtensionContext Type

export interface ControlSettingsExtensionContext {
projectUUID?: string // Project UUID
issueTypeUUID?: string // Work item type UUID
transitionUUID?: string // Transition UUID; only available in transition forms
}
  1. Flow Description:

The plugin passes the edited data back to the ONES via onChange. The ONES listens to onChange and saves the received parameters into the form configuration. During rendering, the configuration is read and passed to the plugin via the settings field.