Oktul home
  • English
  • Estonian

The documentation is in English only.

Contact us

Snippets: dynamic forms

Oktul Code Studio script snippets for dynamic form rules: showing, requiring, limiting and filling fields, copied from the console and run by its tests.

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

Required only on a transition

Resolution notes is required on a transition form and optional elsewhere. context.view says which form is open. The work item view has no required fields, so the rule does nothing there.

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

export default async function (form: Form, context: FormContext) {
const onTransition = context.view === 'IssueTransition' || context.view === 'IssueTransitionAgentView';
form.field('Resolution notes').setVisible(true).setRequired(onTransition);
}

Read only unless in a group

A field is read-only on the form unless the person is in a group. jira.get reads Jira as that person, so the groups are theirs. An automation rule or the REST API can still change the field.

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

export default async function (form: Form) {
const me = await jira.get<{ groups?: { items: { name: string }[] } }>('/rest/api/3/myself', { query: { expand: 'groups' } });
const finance = (me.groups?.items ?? []).some((group) => group.name === 'finance');
form.field('Budget').setReadOnly(!finance).setDescription(finance ? '' : 'Only the finance team changes the budget.');
}

Fill a default as the form opens

setValue fills a field when the form opens. It fills only a field that is empty or still holds the rule’s value, so typed text is kept. The work item view saves a value at once, so there it fills only when a field changes.

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

export default async function (form: Form) {
if (form.trigger !== 'init') return;
const due = new Date(Date.now() + 7 * 24 * 60 * 60 * 1000).toISOString().slice(0, 10);
form.field('duedate').setValue(due);
form.field('labels').setValue(['triage']);
}

Show fields by the value of another

The cost fields show only for a work type that needs them. form.changed is the field that started the run, or null when the form opens. clear() empties a field before it is hidden, because 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) {
const category = form.field('Category').value?.value ?? null;
const hardware = category === 'Hardware';
for (const name of ['Asset tag', 'Purchase cost']) {
const field = form.field(name).setVisible(hardware).setRequired(hardware);
if (!hardware && field.value) field.clear();
}
}

Offer only some choices

A customer request offers only the two lowest priorities. setOptionsVisibility shows or hides up to 100 options by ID. Find the IDs in the field’s options in Jira’s field administration.

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

export default async function (form: Form, context: FormContext) {
if (!context.requestTypeId) return;
form.field('priority').setOptionsVisibility(['4', '5'], true);
}

Rename a field and say what it is for

setName and setDescription change a field’s label and help on this form only, here per space from context.projectId. The field keeps its name everywhere else.

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

export default async function (form: Form, context: FormContext) {
const hr = context.projectId === '10010';
form.field('Summary').setName(hr ? 'Request title' : 'Summary');
form.field('Description').setDescription(hr ? 'Do not write personal codes or health data here.' : '');
}

Fill a field from what Jira knows

Fills Team with the reporter’s team when the form opens, read from their profile property. With no property, the field is left alone. jira.get reads only /rest/api/3/, /rest/agile/1.0/ and /rest/servicedeskapi/, as the person.

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

export default async function (form: Form, context: FormContext) {
if (form.trigger !== 'init' || !context.accountId) return;
try {
const team = await jira.get('/rest/api/3/user/properties/team', { query: { accountId: context.accountId } });
if (team?.value) form.field('Team').setValue(String(team.value));
} catch {
return;
}
}

Rules for one request type

context.requestTypeId and context.portalId are set on a portal request form and on an agent form with a request type chosen, and null elsewhere. form.has says whether a field is on the form.

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

export default async function (form: Form, context: FormContext) {
const laptop = context.requestTypeId === '17';
if (form.has('Delivery address')) form.field('Delivery address').setVisible(laptop).setRequired(laptop);
form.field('Description').setDescription(laptop ? 'Say which model and when you need it.' : '');
}

Read every field on the form

form.fields lists every field on the form with its ID, name, type, value, visibility, required and read-only state, and description. This one adds a reminder to each empty required field.

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

export default async function (form: Form) {
for (const field of form.fields) {
const empty = field.value === null || field.value === '' || (Array.isArray(field.value) && field.value.length === 0);
if (field.required && empty) field.setDescription('Required before you can create the work item.');
}
}

A problem or a question? Write to support@oktul.com or open a request in the Help Center (opens in a new tab).