Pomodoro Timer
This workflow supports the Pomodoro time management and time tracking technique. Pomodoro was created by Francesco Cirillo in the 1980s. For details, visit http://cirillocompany.de/pages/pomodoro-technique/.
To enable this workflow:
Enable and configure time tracking for your project.
Add an enumerated field with the name Pomodoro state to your project. Add the values Timer's running, Not set, Timer finished, and On a break to the field.
Add an enumerated field with the name Pomodoro interruption to your project. Add the values Boss interrupted, Facebook chat, Phone call, and Urgent email to the field.
Add an integer-type field with the name Pomodoro countdown to your project.
Attach the Pomodoro Timer workflow to your project.
Use Case
This workflow lets users follow the Pomodoro time management strategy. The Pomodoro technique works like this:
Periods of activity are divided into equal intervals of time, which are called "pomodoros."
A traditional pomodoro is 30 minutes long: 25 minutes of work plus a 5-minute break.
Every four pomodoros, you are allowed to take a longer break of 15 to 30 minutes.
A pomodoro cannot be interrupted or split up. It marks 25 minutes of pure work.
If interruptions occur, you stop your pomodoro and log the cause of the interruption.
Modules
This workflow includes three modules.
Define transitions for "State" field with Pomodoro timer
The first module contains a state-machine rule that defines how a Pomodoro transitions from state to state. The beauty of this rule is that for each finished or interrupted Pomodoro, YouTrack automatically adds a new work item. It automatically logs your work on a particular issue!
var entities = require('@jetbrains/youtrack-scripting-api/entities');
var workflow = require('@jetbrains/youtrack-scripting-api/workflow');
exports.rule = entities.Issue.stateMachine({
title: workflow.i18n('Define transitions for "State" field with Pomodoro timer'),
fieldName: 'Pomodoro state',
states: {
'Not set': {
initial: true,
transitions: {
start: {
targetState: 'Timer’s running'
}
}
},
'Timer’s running': {
onEnter: function(ctx) {
ctx.issue.fields['Pomodoro interruption'] = null;
workflow.message(workflow.i18n('25 minutes pomodoro is started.'));
ctx.issue.fields['Pomodoro countdown'] = 25;
},
transitions: {
interrupt: {
targetState: 'Not set',
action: function(ctx) {
ctx.issue.fields.required(ctx['Pomodoro interruption'], workflow.i18n('Please specify the interruption cause.'));
ctx.issue.applyCommand(addWorkToday(
(25 - ctx.issue.fields['Pomodoro countdown']) + 'm',
workflow.i18n('Pomodoro was interrupted. The cause: \'') +
ctx.issue.fields['Pomodoro interruption'].name +
'\'.'
));
ctx.issue.fields['Pomodoro countdown'] = null;
}
},
reminder: {
targetState: 'Timer finished',
after: minutes(25)
}
}
},
'Timer finished': {
transitions: {
'take a break': {
targetState: 'On a break',
action: function(ctx) {
workflow.message(workflow.i18n('5 minutes break.'));
ctx.issue.applyCommand(addWorkToday('25m', '+1 pomodoro.'));
ctx.issue.fields['Pomodoro countdown'] = 5;
}
},
'discard': {
targetState: 'Not set',
action: function(ctx) {
ctx.issue.fields.required(ctx['Pomodoro interruption'], workflow.i18n('Please specify the interruption cause.'));
ctx.issue.applyCommand(addWorkToday(
'25m',
workflow.i18n('Pomodoro was discarded. The cause: \'') +
ctx.issue.fields['Pomodoro interruption'].name +
"'."
));
ctx.issue.fields['Pomodoro countdown'] = null;
}
}
}
},
'On a break': {
transitions: {
start: {
targetState: 'Timer’s running',
action: function(ctx) {
ctx.issue.applyCommand(addWorkToday(
(5 - ctx.issue.fields['Pomodoro countdown']) + 'm',
workflow.i18n('+1 short break.')
));
}
},
reminder: {
targetState: 'Not set',
after: minutes(5),
action: function(ctx) {
ctx.issue.applyCommand(addWorkToday('5m', workflow.i18n('+1 break.')));
}
}
}
}
},
requirements: {
'Pomodoro interruption': {
type: entities.EnumField.fieldType
},
'Pomodoro countdown': {
type: entities.Field.integerType
},
'Pomodoro state': {
type: entities.EnumField.fieldType
}
}
});
function minutes(m) {
return m * 60 * 1000;
}
function addWorkToday(countdown, message) {
return 'add work Today ' + countdown + ' ' + message;
}
Enable Pomodoro countdown
The second module contains an on-schedule rule that runs the timer and invokes a 25-minute countdown.
var entities = require('@jetbrains/youtrack-scripting-api/entities');
var workflow = require('@jetbrains/youtrack-scripting-api/workflow');
exports.rule = entities.Issue.onSchedule({
title: workflow.i18n('Enable Pomodoro countdown'),
search: 'has: {Pomodoro countdown} AND Pomodoro countdown: -0 AND (Pomodoro state: {Timer’s running} OR Pomodoro state: {On a break})',
cron: '0 * * * * ?',
action: function(ctx) {
var issueFields = ctx.issue.fields;
issueFields['Pomodoro countdown'] -= 1;
},
requirements: {
'PomodoroCountdown': {
name: 'Pomodoro countdown',
type: entities.Field.integerType
},
'PomodoroState': {
name: 'Pomodoro state',
type: entities.EnumField.fieldType,
}
}
});
Block changes to interruption cause without stopping timer
The last module contains an on-change rule that prevents the user from changing the cause of an interruption (by entering a value in the Pomodoro interruption field) without stopping the timer.
// The Pomodoro technique is a time management method created by Francesco Cirillo in the 1980s.
var entities = require('@jetbrains/youtrack-scripting-api/entities');
var workflow = require('@jetbrains/youtrack-scripting-api/workflow');
exports.rule = entities.Issue.onChange({
title: workflow.i18n('Block changes to interruption cause without stopping timer'),
guard: function(ctx) {
var issueFields = ctx.issue.fields;
return issueFields.isChanged(ctx.PomodoroInterruption) && !issueFields.isChanged(ctx.PomodoroState);
},
action: function() {
workflow.check(
false,
workflow.i18n('Cannot change the interruption cause without changing the timer state.')
);
},
requirements: {
'PomodoroInterruption': {
name: 'Pomodoro interruption',
type: entities.EnumField.fieldType
'Boss interrupted': {},
'Facebook chat': {},
'Phone call': {},
'Urgent email': {}
},
'PomodoroState': {
name: 'Pomodoro state',
type: entities.EnumField.fieldType
}
}
});
Last modified: 28 October 2020