Scripted Fields
Scripted Fields are custom fields whose values are computed by a script rather than entered manually. They run a JavaScript calculation whenever the field is rendered and display the result on the issue view.
How Scripted Fields Work
- You create a Scripted Field with a script that computes a value
- The field appears on issues just like any other custom field
- When an issue is viewed, ScriptForge runs your script and renders the result
- The computed value is displayed (as text, number, or paragraph)
Field Types
ScriptForge supports three custom field types:
| Type | Output | Use Case |
|---|---|---|
| String | Single line of text | Status labels, computed names, concatenations |
| Number | Numeric value | Calculations, counts, scores |
| Paragraph | Multi-line text / rich content | Summaries, generated reports, formatted data |
Creating a Scripted Field
- Navigate to Apps → ScriptForge → Scripted Fields
- Click Create Scripted Field
- Configure:
- Name: The field label shown on issues
- Description: What this field calculates
- Type: String, Number, or Paragraph
- Script: JavaScript that returns the computed value
- Click Save
After creation, add the field to your issue screens through Jira's field configuration (just like any custom field).
Script Context
Your script has access to the current issue's data and the full HAPI library:
// 'issue' context provides the current issue key
const issue = await WorkItems.getByKey(context.issueKey);
Real-World Examples
Calculate days since creation
const issue = await WorkItems.getByKey(context.issueKey);
const created = new Date(issue.created);
const now = new Date();
const days = Math.floor((now - created) / (1000 * 60 * 60 * 24));
return days;
Type: Number
Count sub-tasks
const issue = await WorkItems.getByKey(context.issueKey);
const subtasks = await issue.getSubTaskObjects();
return subtasks.length;
Type: Number
Show completion percentage
const issue = await WorkItems.getByKey(context.issueKey);
const subtasks = await issue.getSubTaskObjects();
if (subtasks.length === 0) return 'No sub-tasks';
const done = subtasks.filter(s => s.status === 'Done').length;
const pct = Math.round((done / subtasks.length) * 100);
return `${pct}% (${done}/${subtasks.length})`;
Type: String
Generate a risk label based on multiple factors
const issue = await WorkItems.getByKey(context.issueKey);
const priority = issue.priority;
const dueDate = issue.dueDate ? new Date(issue.dueDate) : null;
const now = new Date();
let risk = 'Low';
if (priority === 'Critical' || priority === 'High') {
risk = 'Medium';
}
if (dueDate && dueDate < now) {
risk = 'High';
}
if (priority === 'Critical' && dueDate && dueDate < now) {
risk = 'Critical';
}
return risk;
Type: String
Performance
- Scripted fields execute each time the issue is rendered (viewing the issue, appearing in a list, etc.)
- Keep scripts fast — avoid complex JQL searches or multiple API calls
- Results are not cached between views; the script runs fresh each time
- Heavy calculations should consider using Entity Properties (written by a listener) and reading the stored value instead