I want to prevent users in YouTrack from modifying or adding workitems in the past. They should only add/modify workitems in current day.
In YouTrack workflows i can detect changed Spent time event and prevent users from adding workitem. But I want to get an event when user is modifying workitem in JavaScript workflows. Here is my code:
var entities = require('#jetbrains/youtrack-scripting-api/entities');
var workflow = require('#jetbrains/youtrack-scripting-api/workflow');
exports.rule = entities.Issue.onChange({
title: workflow.i18n('Disable editing workitems'),
guard: function(ctx) {
return ctx.issue.fields.isChanged(ctx.ST);
},
action: function(ctx) {
workflow.check(ctx.issue.workItems.added.isEmpty(), workflow.i18n('You can add/modify workitems only in current day.'));
},
requirements: {
ST: {
type: entities.Field.periodType,
name: 'Spent Time'
}
}
});
Datetime conditions are omitted...
Check for ctx.issue.workItems.isChanged and also check the content of ctx.issue.editedWorkItems set.
Not sure if its still relevant, but I have full example:
/**
* This is a template for an on-change rule. This rule defines what
* happens when a change is applied to an issue.
*
* For details, read the Quick Start Guide:
* https://www.jetbrains.com/help/youtrack/server/2022.2/Quick-Start-Guide-Workflows-JS.html
*/
const entities = require('#jetbrains/youtrack-scripting-api/entities');
const workflow = require('#jetbrains/youtrack-scripting-api/workflow');
exports.rule = entities.Issue.onChange({
title: 'Prevent-workitem-updates-past',
guard: (ctx) => {
const issue = ctx.issue;
const fs = issue.fields;
// NOT using issue.workItems.added.isEmpty() , because we also want to detect EDITS as well as ADDS to the WorkItems array.
return fs.isChanged(ctx.ST) && !issue.becomesReported;
},
action: (ctx) => {
const issue = ctx.issue;
function checkWorkItemDate(currentWorkItem, currentEpochTimeStamp){
workflow.check(currentWorkItem.date == currentEpochTimeStamp, workflow.i18n('You can add/modify workitems only in current day.'));
}
//const splittedDate = new Date().toISOString().slice(0, 10).split('-');
//const currentEpoch = new Date(splittedDate[0], splittedDate[1] - 1, splittedDate[2]).valueOf();
const currentDate = new Date();
const currentEpoch = new Date(currentDate.getFullYear(), currentDate.getMonth(), currentDate.getDate()).valueOf();
// Check newly added elements
issue.workItems.added.forEach(workItem => {
checkWorkItemDate(workItem, currentEpoch);
});
// Check edited elements
issue.editedWorkItems.forEach(workItem => {
checkWorkItemDate(workItem, currentEpoch);
});
workflow.check(true);
},
requirements: {
ST: {
type: entities.Field.periodType,
name: 'Spent Time'
}
}
});
Related
For example:
object1(1) = {
name: 'Rhodok Sergeant',
speciality: 'Hand to hand battle'
}
then I want to update only the speciality field, into:
object1(1) = {
name: 'Rhodok Sergeant',
speciality: 'Long range battle'
}
Thank you.
This is possible using following steps -
fetch the item first using idbcursor
update that item
call cursor.update to store updated data in indexedb.
An example code is -
const transaction = db.transaction(['rushAlbumList'], 'readwrite');
const objectStore = transaction.objectStore('rushAlbumList');
objectStore.openCursor().onsuccess = function(event) {
const cursor = event.target.result;
if (cursor) {
if (cursor.value.albumTitle === 'A farewell to kings') {
const updateData = cursor.value;
updateData.year = 2050;
const request = cursor.update(updateData);
request.onsuccess = function() {
console.log('data updated');
};
};
cursor.continue();
}
};
Check out this link for more info - https://developer.mozilla.org/en-US/docs/Web/API/IDBCursor/update
Note:- In above code, i am looping through all records which is not efficient in case you want to fetch the particular record based on some condition. So you can use idbKeyRange or some other idb query alternative for this.
you cannot do partial updates, you can only overwrite an entire object
read the object in from memory, change it, and then write it back
I want to copy the value from issues in one project to issues in another that depend on it.
That is what I have:
var entities = require('#jetbrains/youtrack-scripting-api/entities');
var workflow = require('#jetbrains/youtrack-scripting-api/workflow');
exports.rule = entities.Issue.onChange({
// TODO: give the rule a human-readable title
title: 'Date-propagation',
guard: function(ctx) {
var links = ctx.issue.links['depends on'];
return ctx.issue.isChanged("Date") || !links.added.isEmpty() || !links.removed.isEmpty();
},
action: function(ctx) {
var issue = ctx.issue;
var links = issue.links['depends on'];
function updateIssue(normalIssue){
normalIssue.fields.DueDate = issue.fields.Date.value;
}
function checkList(list){
if(list.isNotEmpty())list.forEach(function(normalIssue){updateIssue(normalIssue);}) ;
}
//checkList(links.removed);
checkList(links);
// TODO: specify what to do when a change is applied to an issue
},
requirements: {
Date: {
type: entities.Field.dateType,
},
Depend: {
type: entities.IssueLinkPrototype,
outward: 'is required for',
inward: "depends on"
}
}
});
The problem is in this line:
normalIssue.fields.DueDate = issue.fields.Date;
How should it be done?
Most probably, you do not have a 'DueDate' field on your instance (as the default field is called 'Due Date'). If so, your code line should look like this:
normalIssue.fields['Due Date'] = issue.fields.Date;
I am using prosemirror to build a collaborative editor, where multiple people can edit one document. I wrote the following code, based on the example given here - http://prosemirror.net/docs/guides/collab/
Here is the code-
const { EditorState } = require('prosemirror-state');
const { EditorView } = require('prosemirror-view');
const { DOMParser } = require("prosemirror-model");
const {schema} = require("./schema");
var collab = require("prosemirror-collab");
function Authority(doc) {
this.doc = doc
this.steps = []
this.stepClientIDs = []
this.onNewSteps = []
}
Authority.prototype.receiveSteps = function(version, steps, clientID) {
if (version != this.steps.length) return
var self = this
// Apply and accumulate new steps
steps.forEach(function(step) {
self.doc = step.apply(self.doc).doc
self.steps.push(step)
self.stepClientIDs.push(clientID)
})
// Signal listeners
this.onNewSteps.forEach(function(f) { f() })
}
Authority.prototype.stepsSince = function(version) {
return {
steps: this.steps.slice(version),
clientIDs: this.stepClientIDs.slice(version)
}
}
var auth = new Authority('');
collabEditor(auth)
function collabEditor(authority) {
var view = new EditorView(document.querySelector("#editor"), {
state: EditorState.create({schema: schema, plugins: [collab.collab()]}),
dispatchTransaction: function(transaction) {
var newState = view.state.apply(transaction)
view.updateState(newState)
var sendable = collab.sendableSteps(newState)
if (sendable)
authority.receiveSteps(sendable.version, sendable.steps,
sendable.clientID)
}
})
authority.onNewSteps.push(function() {
var newData = authority.stepsSince(collab.getVersion(view.state))
view.dispatch(
collab.receiveTransaction(view.state, newData.steps, newData.clientIDs))
})
return view
}
When i run this code (after installing all the dependencies and setting up a simple server in nodejs) I am basically able to edit a text box but I am not able to open two tabs in chrome and see the collaboration happen. What am i doing wrong?
Will love some feedback.
This is the example code for a simple, single-page, no-external-communication setup. As such, no, it won't communicate to other tabs. For that, you'd have to move the authority somewhere else and set up pages to actually communicate with it over HTTP or websockets. (See for example this demo.)
Hoping someone out there could tell me where I am going wrong with this update method:
changeTaskDetails: function(singleID,detailsTarget){
TaskDetails.update({
_id: singleID,
}, {
$set:{
projectType: detailsTarget,
}
});
console.log(singleID);
},
Here is the event:
'submit #editTaskDetails'(event){
event.preventDefault();
var id = FlowRouter.getParam('taskId');
const singleDetailsUpdate = Tasks.findOne({_id:id});
const singleID = singleDetailsUpdate._id;
const target = event.target;
const facilityTarget = target.facilityName.value;
const inspectorTargetName = target.detailsinspector.value;
const inspectorIdTarget = target.inspectorid.value;
const detailsTarget = target.detailstype.value;
const dateTarget = target.TaskDate.value;
console.log(singleID)
Meteor.call("changeTaskDetails", singleID,detailsTarget);
},
I can get the 2 props to log...but its not updating the DB. No errors in either console.
I figured it out! I had a session variable controlling when you could (or could not) see the update form. For one reason or another the form crapped out when inside of this area. When I removed the session, and added the form to the main template...it worked!
I've been trying to update a single field using db.put() but couldn't make it work properly. Every time I update a single field by a given ID, it deletes all other entries. Here is an example code:
var schema = {
stores: [
{
name: 'items',
keyPath: 'id'
},
{
name: 'config',
keyPath: 'id'
}
]
};
var db = new ydn.db.Storage('initial', schema);
var items = [{
id: 1,
itemId: 'GTA5',
date:'03/25/2013',
description:'Great game'
}, {
id: 2,
itemId: 'Simcity',
date:'12/01/2012',
description:'Awesome gameplay'
}];
var config = {
id: 1,
currency: 'USD'
};
db.put('items', items);
db.put('config', config);
var updateTable = function(){
var req = $.when(db.count('items'),db.values('items'),db.get('config', 1));
var disp = function(s) {
var e = document.createElement('div');
e.textContent = s;
document.body.appendChild(e);
};
req.done(function(count,r,config) {
var currency = config.currency;
if(count > 0){
var n = r.length;
for (var i = 0; i < n; i++) {
var id = r[i].id;
var itemId = r[i].itemId;
var date = r[i].date;
var description = r[i].description
disp('ID: '+id+' itemID: '+itemId+' Currency: '+currency+' Date: '+date+' Description: '+description);
}
}
});
}
updateTable();
$('a').click(function(e){
e.preventDefault();
db.put('items',{id:2,description:'Borring'}).done(function(){
updateTable();
});
});
Here is a working example of whats happening JSFiddle. If you click the "change" link, the specified field is updated but all other fields are 'undefined'
Yeah, SimCity is boring now, but Tomorrow will bring excitement again.
IndexedDB is essentially a key-document store. You have to read or write a record as a whole. It is NOT possible to update only certain field(s). Event if you want small update, you have to read and write back whole record.
Reading and write back the whole record is OK, but there is an important consideration for consistency. When you write back, you must ensure that the the record you have was not modified by other thread. Even though javascript is single thread, since both read and write operations are asynchronous and each operation could have different database state. It seems extremely rare, but often happen. For example, when user click, nothing happen and then click again. These user interactions are queued and execute in parallel from async database perspective.
A common technique is using single transaction for both operations. In YDN-DB, you can do in three ways.
Using explicit transaction:
db.run(function(tx_db) {
tx_db.get('items', 2).done(function(item) {
item.description = 'boring until Tomorrow';
tx_db.put(item).done(function(k) {
updateTable();
}
}
}, ['items'], 'readwrite');
Using an atomic database operation:
var iter = ydn.db.ValueIterator.where('items', '=', 2);
db.open(function(cursor) {
var item = cursor.getValue();
item.description = 'boring until Tomorrow';
cursor.update(item);
}, iter, 'readwrite');
EDIT:
Using query wrapper:
db.from('items', '=', 2).patch({description: 'boring until Tomorrow'});