Skip to content

Snippets: scripted fields

These are the snippets the console’s Snippets dialog offers under Scripted fields. Each is TypeScript; in a .js script the console shows the same code with its types removed. Every one runs unchanged in Code Studio’s own tests. How the API they call behaves is in writing scripts and the script API reference.

Percent of subtasks done

For a Code Studio number field: the share of a work item’s subtasks that are done, read from the work item Jira hands the script. No subtasks gives an empty field.

interface WorkItem {
fields?: { subtasks?: { fields?: { status?: { statusCategory?: { key?: string } } } }[] };
}
export default async function (workItem: WorkItem) {
const subtasks = workItem.fields?.subtasks ?? [];
if (subtasks.length === 0) return null;
const done = subtasks.filter((subtask) => subtask.fields?.status?.statusCategory?.key === 'done').length;
return Math.round((done / subtasks.length) * 100);
}

Minutes since the last update

For a Code Studio number field whose value moves with time: set Recompute to about every 15 minutes on the field, in Scripted fields, and the value is never more than a refresh behind. Each refresh is one run over the context’s work items.

export default async function (workItem: { fields?: { updated?: string } }) {
const updated = workItem.fields?.updated ? Date.parse(workItem.fields.updated) : NaN;
if (Number.isNaN(updated)) return null;
return Math.max(0, Math.floor((Date.now() - updated) / 60_000));
}

Count what a query finds for each work item

For a Code Studio number field: how many open work items block this one, counted with JQL. Each work item is one count request, so keep the query narrow.

export default async function (workItem: { key: string }) {
const found = await jira.post<{ count: number }>('/rest/api/3/search/approximate-count', {
jql: `issue in linkedWorkItems("${workItem.key}", "is blocked by") AND statusCategory != Done`,
});
return found.count;
}

Pick a choice from other fields

For a Code Studio select: the risk from the priority and the due date. options() lists the choices, which Code Studio stores on the field; a value outside them is not stored.

interface WorkItem {
fields?: { priority?: { name?: string }; duedate?: string | null };
}
export default async function (workItem: WorkItem) {
const priority = workItem.fields?.priority?.name ?? 'Medium';
const due = workItem.fields?.duedate ? Date.parse(workItem.fields.duedate) : null;
const soon = due !== null && due - Date.now() < 3 * 24 * 60 * 60 * 1000;
if (priority === 'Highest' || (priority === 'High' && soon)) return 'High';
return soon ? 'Medium' : 'Low';
}
export function options() {
return ['Low', 'Medium', 'High'];
}

Select: choices from Jira, a default

For a Code Studio select, multi select, radio buttons or checkboxes: options() reads the choices, here the space’s components, and the default export gives a new work item’s default. People pick on the create screen, the work item and the portal. options() runs when the script is published and with Refresh choices in Scripted fields; set Recompute on the field to read the choices again as the components change. A value someone chose stays.

interface Component {
name: string;
}
export function options() {
return jira.get<Component[]>('/rest/api/3/project/DEMO/components').then((components) => components.map((component) => component.name));
}
export default async function () {
return 'Platform';
}

User picker: offer the members of a group

For a Code Studio user picker: options() lists the account ids a person may pick, here a group’s members, with names Code Studio shows; the default export makes the reporter the default. With no options() export, anyone can be picked.

interface Members {
values: { accountId: string; displayName: string }[];
isLast: boolean;
}
export async function options() {
const people: { value: string; label: string }[] = [];
for (let startAt = 0; ; startAt += 50) {
const page = await jira.get<Members>('/rest/api/3/group/member', { query: { groupname: 'approvers', startAt, maxResults: 50 } });
people.push(...(page.values ?? []).map((member) => ({ value: member.accountId, label: member.displayName })));
if (page.isLast !== false || people.length >= 200) break;
}
return people;
}
export default async function (workItem: { fields?: { reporter?: { accountId?: string } } }) {
return workItem.fields?.reporter?.accountId ?? null;
}

Group picker: offer the support teams

For a Code Studio group picker: options() lists the group ids a person may pick, here every group whose name starts with team-. A group field offers nothing until options() lists some.

interface Found {
groups: { name: string; groupId: string }[];
}
export async function options() {
const found = await jira.get<Found>('/rest/api/3/groups/picker', { query: { query: 'team-', maxResults: 50 } });
return (found.groups ?? []).map((group) => ({ value: group.groupId, label: group.name }));
}
export default async function () {
return null;
}

Labels from the components

For a Code Studio labels field: one word per component, lower case with no spaces, so the field can be searched with JQL.

export default async function (workItem: { fields?: { components?: { name: string }[] } }) {
return (workItem.fields?.components ?? []).map((component) => component.name.toLowerCase().replace(/\s+/g, '-'));
}

A problem or a question? Write to support@oktul.com or open a request in the Help Center (opens in a new tab). Both reach the same service desk, so either way the request gets a reference and an SLA measuring the response.