Oktul home
  • English
  • Estonian

The documentation is in English only.

Contact us

Snippets: starting points

Oktul Code Studio script snippets for scripts started by a listener, an API trigger, a rule or a schedule, copied from the console and run by its tests.

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 lists what an update changed. An API trigger can run the same script when its JSON body is that payload, for example from an automation rule’s Send web request.

export default async function (event: JiraWorkItemEvent, context: ListenerContext) {
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. The key comes from { “key”: “DEMO-1” } or from ?key=DEMO-1.

export default async function (event: ApiTriggerEvent<{ key?: string }>, context: ApiTriggerContext): Promise<ApiTriggerResponse> {
const key = event.body?.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 run was due, so a late start still covers the right day. This one finds the work items updated in the day before.

export default async function (event: ScheduleEvent, context: ScheduleContext) {
const due = new Date(event.scheduledFor);
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 holds the rule’s parameters with smart values filled in, and event.issue is the work item the rule ran on. costCentre has a default, so Test event works without parameters.

export default async function (event: AutomationEvent<{ costCentre?: string }>, context: AutomationContext) {
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 also export options() to list its choices.

export default async function (workItem: FieldWorkItem, context: FieldContext) {
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(context: FieldContext) {
return ['Low', 'Medium', 'High'];
}

Change a form while it is filled in

For a dynamic form. It runs in the browser of the person filling in the form, when it opens and when a field it reads changes. This one shows a field and makes it required only for the highest priority. Jira still saves a hidden field.

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

export default async function (form: Form, context: FormContext) {
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).