Integrate CFS custom fields

Custom Field Suite brings you the most common custom field types to boost the user experience and customize Jira to suit various use cases. The JQL filter is compatible with all custom field types.

👏Our custom field types:

Vision

  • Work together with customers and build custom field types based on their use cases

  • Cooperation with Jira consultants in order to collect valuable use case and build customer success stories

  • Focus in Forge to support Atlassian as much as possible

MoSCoW

Two values are being stored inside of the configuration. Those are Text and Color. Both values are being saved by using the storage API: https://developer.atlassian.com/platform/forge/runtime-reference/storage-api/ We store them as JSON format with key “moscow-config”. When rendering the field in View Issue Screen, we just pull both values from the storage and pass them to the StatusLozenge component: https://developer.atlassian.com/platform/forge/ui-kit-components/text/#StatusLozenge It accepts 2 parameters: text and appearance (color).

T-Shirt

This field has hardcoded values that can be turned on and off. Descriptions can be changed also. Both values are saved by using the storage API. When rendering the value in View Issue Screen, depending on the selected value in the field, we render an SVG image and display it in the field. All SVG images are represented as HTML and are located inside the CFS app.

Progress / Completed Issues in Epic / Completed Story Points in Epic / Unsized issues in Epic

Completed issues in epic, Completed story points in Epic and Unsized issues in Epic are all hardcoded fields

The progress bar is being loaded through our own component. Basically, it's an SVG image that takes a parameter (number). The number is the value of the custom field. It represents a percentage, so one can only select values from 0 to 100. We pass the selected number to the progress bar’s HTML and render the SVG image. There is also a tooltip for displaying the percentage. The tooltip is part of the Forge UI. The configuration is used for saving the color. Colors are hardcoded by using their hexadecimal representations and are saved by using the storage API.

Completed Issues in Epic and Completed Story Points in Epic fields use the same logic as the progress bar. We get the color from the configuration (separate configuration page for each field). The only difference is that both of these fields are calculated fields, which means that the user can’t define values for these fields. Completed Issues in Epic field returns the percentage of completed issues in epics. Completed Story Points in Epic field returns the percentage of completed story points in epics, meaning it calculates story points of completed issues in comparison to all issues in epics.

1 2 3 // Loading the progress bar const calculatedProgress = progress !== 0 && progress !== null ? progress * 2 : ""; return `<svg xmlns="http://www.w3.org/2000/svg" width="204" height="4"><g fill="none" fillRule="evenodd"><path d="M2 0h200a1.5 1.5 0 0 1 0 4h-200a1.5 1.5 0 1 1 0-4z" fill="#DFE1E6" /><path d="M2 0h${calculatedProgress}a1.5 1.5 0 0 1 0 4h-${calculatedProgress}a1.5 1.5 0 0 1 0-4z" fill="${builtColor}" /></g></svg>`;

Traffic Lights

The traffic lights field works almost the same as the t-shirt field. Depending on the selected value in the field, we render our own SVG images through HTML codes, which are defined inside our own CFS app. All 3 traffic light fields are hardcoded and are not changeable. We use a tooltip from the Forge UI for displaying the description of each traffic light. Descriptions can be configured in the configuration. They are being saved by using the storage API.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 // Traffic light images red: `<svg width="200" height="16" xmlns="http://www.w3.org/2000/svg"> <g fill="none" fill-rule="evenodd"> <path d="M0 0h200v16H0z"/> <rect fill="#403C3C" width="46" height="16" rx="2"/> <circle fill="#F42834" cx="8.667" cy="8" r="6"/> <circle fill="#C3B9B9" opacity=".15" cx="23" cy="8" r="6"/> <circle fill="#C3B9B9" opacity=".15" cx="37.333" cy="8" r="6"/> </g> </svg>`, yellow: `<svg width="200" height="16" xmlns="http://www.w3.org/2000/svg"> <g fill="none" fill-rule="evenodd"> <path d="M0 0h200v16H0z"/> <rect fill="#403C3C" width="46" height="16" rx="2"/> <circle fill="#C3B9B9" opacity=".15" cx="8.667" cy="8" r="6"/> <circle fill="#FEF22F" cx="23" cy="8" r="6"/> <circle fill="#C3B9B9" opacity=".15" cx="37.333" cy="8" r="6"/> </g> </svg>`, green: `<svg width="200" height="16" xmlns="http://www.w3.org/2000/svg"> <g fill="none" fill-rule="evenodd"> <path d="M0 0h200v16H0z"/> <rect fill="#403C3C" width="46" height="16" rx="2"/> <circle fill="#C3B9B9" opacity=".15" cx="8.667" cy="8" r="6"/> <circle fill="#C3B9B9" opacity=".15" cx="23" cy="8" r="6"/> <circle fill="#45B934" cx="37.333" cy="8" r="6"/> </g> </svg>`

Rating

The same technique is being used for the rating field. Depending on the selected value in the field, we render our own SVG images through HTML codes, which are defined inside our own CFS app. They are 5 different SVG images, one for each rating possibility. We use a tooltip from the Forge UI for displaying the description of each rating possibility. Descriptions can be configured in the configuration. They are being saved by using the storage API.

Single select picker (Multiple and Single), Multilevel select picker (Multiple and Single)

No special storing from our side, because each field has its own configuration. No global configuration is needed. Uses Jira’s view context from @forge/bridge for saving values.

Abbreviate

There is no configuration for this field. We simply get the saved value and upon displaying it, we do some formatting to display the number in an abbreviated format.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 // Formatting abbreviated fields const formatNumber = () => { const isNegative = fieldValue < 0; const absValue = Math.abs(fieldValue); let formated = 0; if (absValue < 1e3) formated = absValue; if (absValue >= 1e3 && absValue < 1e6) formated = `${Math.round((absValue / 1e3) * 100 + 0.05) / 100}K`; if (absValue >= 1e6 && absValue < 1e9) formated = `${Math.round((absValue / 1e6) * 100 + 0.05) / 100}M`; if (absValue >= 1e9 && absValue < 1e12) formated = `${Math.round((absValue / 1e9) * 100 + 0.05) / 100}B`; if (absValue >= 1e12) formated = `${Math.round((absValue / 1e12) * 100 + 0.05) / 100}t`; return isNegative ? `-${formated}` : formated; };

Currency

Uses currencies that are hardcoded as objects in an array saved in a .js file. Upon installing the application, those currencies are saved by using the storage API and are being loaded from there for any further use. The currencies can be enabled / disabled on the configuration page, but no other manipulation is allowed.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 // Default currencies (only a part) const currencyDefaultFields = [ { id: "AMD", symbol: "֏", isoCode: "AMD", currency: "Armenian dram", active: true, }, { id: "AUD", symbol: "$", isoCode: "AUD", currency: "Australian dollar", active: true, }, { id: "BAM", symbol: "KM", isoCode: "BAM", currency: "Bosnia and Herzegovina convertible mark", active: true, } ]

Unit

This field has also predefined (hardcoded) values in the configuration, which are saved by the Storage API when the application is installed. Unlike the currency field, here you can add, edit and delete values. There is also a tooltip from the Forge UI, which displays the description defined in the configuration.

Min/Max range

No special storing from our side. Uses Jira’s view context from @forge/bridge for saving values. Allowing only 2 values to be saved: min and max.

Comment

Comment fields are locked. No configuration for these fields. Simply getting necessary data from Jira by using the official REST API.

Sum/Average

No special storing (configuration page) from our side. Uses Jira’s view context from @forge/bridge for saving values. 

Secure fields

For secure fields, there is a global configuration page that uses the Storage API. There is also Jira’s configuration page (specific for each field) which uses the view context from @forge/bridge for saving values. One can define different view and edit permissions for displaying sensitive information based on users, groups, and project roles. Could also be the reporter or current assignee.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // Saving values by using the Storage API try { const storageFields = await storage.get(STORAGE_NAME[name]); if (!storageFields) { await storage.set( STORAGE_NAME[name], defaultFields[`${name}DefaultFields`] ); return defaultFields[`${name}DefaultFields`]; } return storageFields; } catch (e) { console.log("Error:", e); return defaultFields[`${name}DefaultFields`]; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // Saving values by using the view context import { invoke, view } from "@forge/bridge"; const onSubmit = async () => { try { return await view.submit({ configuration: { unit: units ? [...units] : [] }, }); } catch (e) { setErrorMsg({ title: "Something went wrong!", description: "Submiting form failed, please try again.", }); setIsFlag(true); } };