Skip to content

Snippets: starting points

These are the snippets the console’s Snippets dialog offers under Starting points. 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.

React to a work item event

For a listener on work item created or updated: event is the webhook payload, and event.changelog says what an update changed; a created work item has none. The same script runs from an API trigger when the request’s JSON body is that payload, so another system or an automation rule’s Send web request can start it too.

interface WorkItemEvent {
webhookEvent?: string;
issue: { key: string };
user?: { accountId: string };
changelog?: { items: { field: string; fromString: string | null; toString: string | null }[] };
}
export default async function (event: WorkItemEvent) {
const key = event.issue.key;
const status = event.changelog?.items.find((item) => item.field === 'status');
if (event.changelog && !status) return { key, skipped: 'the status did not change' };
log.info(`${key}: ${status ? `${status.fromString} to ${status.toString}` : 'created'} by ${event.user?.accountId ?? 'the app'}`);
return { key, status: status?.toString ?? null };
}

Answer an API trigger

For an API trigger that answers with the script’s result: read the query and the JSON body, and return statusCode, headers and body as the HTTP response. A JSON object body’s fields are on event too, so the key here comes from { “key”: “DEMO-1” } or from ?key=DEMO-1.

interface ApiEvent {
method?: string;
queryStringParams?: Record<string, string>;
body?: { key?: string };
key?: string;
}
export default async function (event: ApiEvent) {
const key = event.key ?? event.queryStringParams?.key ?? 'DEMO-1';
if (!/^[A-Z][A-Z0-9_]+-\d+$/.test(key)) return { statusCode: 400, body: { error: 'Send a work item key, such as DEMO-1.' } };
const item = await jira.get<{ key: string; fields: { summary: string } }>(`/rest/api/3/issue/${key}`, { query: { fields: 'summary' } });
return { statusCode: 200, headers: { 'Cache-Control': 'no-store' }, body: { key: item.key, summary: item.fields.summary } };
}

Run on a schedule

For a schedule: event.scheduledFor is the minute this occurrence was due, so a run that starts late still works on the right day. Here, the work items updated in the day before it.

export default async function (event: { scheduledFor?: string }) {
const due = new Date(event.scheduledFor ?? Date.now());
const since = new Date(due.getTime() - 24 * 60 * 60 * 1000).toISOString().slice(0, 16).replace('T', ' ');
const found = await jira.post<{ issues: { key: string }[] }>('/rest/api/3/search/jql', {
jql: `updated >= "${since}" ORDER BY updated DESC`,
fields: ['summary'],
maxResults: 100,
});
log.info(`${found.issues.length} work items updated since ${since}`);
return { since, keys: found.issues.map((issue) => issue.key) };
}

Use an automation rule’s values

For the Run a Code Studio script action: event.params are the rule’s parameters with Jira’s smart values filled in, event.issue the work item the rule ran on. costCentre has a default, so the script also runs from Test event, which passes no parameters.

interface RuleEvent {
params?: { costCentre?: string };
issue?: { key: string };
}
export default async function (event: RuleEvent) {
const key = event.issue?.key;
if (!key) throw new Error('Run this from a rule on a work item.');
const costCentre = event.params?.costCentre ?? 'Tallinn';
await jira.put(`/rest/api/3/issue/${key}`, { fields: { labels: [`cost-centre-${costCentre.toLowerCase()}`] } });
return { key, costCentre };
}

Compute a scripted field

For a scripted field: the default export gets the work item with every field and returns the value, here the days since it was created. A select field can add export function options() returning its choices.

interface WorkItem {
key?: string;
fields?: { created?: string };
}
export default async function (workItem: WorkItem) {
const created = Date.parse(workItem.fields?.created ?? new Date().toISOString());
return Math.floor((Date.now() - created) / (24 * 60 * 60 * 1000));
}
/** Only for a select field: the choices people and the script pick from. */
export function options() {
return ['Low', 'Medium', 'High'];
}

Change a form while it is filled in

For a dynamic form: runs in the browser of whoever has the Jira form open, as it opens and when a field it reads changes. Here, a field is shown and required only for the highest priority. Hiding a field is not a control: Jira still saves it.

Runs in the browser of whoever fills in the form, not in a run.

export default async function (form, context) {
const priority = form.field('priority');
form.field('customfield_10050')
.setVisible(priority.value?.name === 'Highest')
.setRequired(priority.value?.name === 'Highest');
}

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.